Skip to content
🎉 GoReleaser v2.15 is out! with Flatpak, SRPM, and more!

Node.js

This feature is currently experimental. Feedback is greatly appreciated!

You can build Node.js Single Executable Application (SEA) binaries with GoReleaser!

Warning

Only Node ≥ v25.5.0 is supported.

Configuration

Simply set the builder to node, for instance:

.goreleaser.yaml
builds:
  - id: my-build
    builder: node

    # Binary name.
    # Can be a path (e.g. `bin/app`) to wrap the binary in a directory.
    #
    # Default: Project directory name.
    binary: program

    # Entrypoint script bundled into the SEA blob.
    #
    # Default: 'index.js'.
    # Templates: allowed.
    main: index.js

    # Targets, in nodejs.org/dist format.
    # Default: all of: darwin-arm64, darwin-x64, linux-arm64, linux-x64,
    #                  win-arm64, win-x64.
    targets:
      - linux-x64
      - darwin-arm64

    # Path to the project's (sub)directory containing the code and
    # (typically) package.json.
    #
    # Default: '.'.
    dir: my-app

    # Set a specific node binary to use when building the SEA bundle.
    # It is safe to ignore this option in most cases.
    #
    # Default: "node".
    # Templates: allowed.
    tool: "node-nightly"

    # Custom environment variables to set when invoking node.
    # Invalid environment variables will be ignored.
    #
    # Default: os.Environ() ++ env config section.
    # Templates: allowed.
    env:
      - FOO=bar

    # Hooks can be used to customize the final binary, for example to
    # bundle the entrypoint or sign the produced executable.
    #
    # Templates: allowed.
    hooks:
      post: ./script.sh {{ .Path }}

    # If true, skip the build.
    skip: false

Environment setup

GoReleaser will not install Node.js, project dependencies, or run your JavaScript build for you. Run them before GoReleaser, usually with a global before hook:

.goreleaser.yaml
before:
  hooks:
    - npm ci
    - npm run build

Do not write your JavaScript build output to the dist directory. GoReleaser requires that directory to be empty after before hooks run. Configure your bundler to write somewhere else, for example build/, and point main at the generated entrypoint.

Caveats

The following standard build fields are intentionally not supported by the node builder:

  • command, flags — the SEA pipeline invokes node directly with a known set of arguments.

The following template variables are available in the per-target build context: .Os, .Arch, .Goos, .Goarch, .Target, .Name, .Path, .Ext, .Env.*. Use them in main, env, and the hooks recipes.

Tuning the SEA blob (sea-config.json)

Drop a sea-config.json file alongside your package.json (i.e. in the build’s dir) and GoReleaser will merge it with its own GoReleaser-owned fields before invoking node --build-sea:

sea-config.json
{
  "assets": {
    "schema.json": "./schema.json"
  },
  "execArgv": ["--max-old-space-size=4096"],
  "disableExperimentalSEAWarning": true
}

GoReleaser always overwrites output, executable, main — these point at internal cache paths, so any user-supplied values are ignored. Relative paths under assets are anchored at the build directory so they keep resolving after GoReleaser moves the merged configuration into a scratch directory.

When no sea-config.json is present, GoReleaser generates the minimum config needed to drive node --build-sea. See Node’s Single Executable Applications docs for the full list of accepted fields.

Version resolution

The target Node.js version comes from engines.node in package.json. Exact versions (v25.5.0, 25.5.0) and ranges (>=25.5 <26, ^25) are accepted. Pin an exact version for reproducible release artifacts.

Learn more about the template language.
Last updated on