夯HumGuides
Back to home

Deployment

Start with a standalone build: copy the output to your server and run it without installing npm dependencies. If your dependencies need their installed files, use a non-standalone build and deploy its production dependencies alongside it.

Standalone: build and copy

Add standalone: true to your existing Hum plugin options in the Vite configuration, keeping the other plugins:

TypeScript
// Add standalone to your existing Hum plugin options.
// Keep your other Vite plugins.
hum({ devEntry: "app.ts", standalone: true })

Build the application, then start it locally to check the result:

Shell
npm run build
node dist/server.js

Copy the entire dist/ directory to your server and run node dist/server.js there using Node.js 22.18 or later. Server dependencies are bundled into ESM server.js; Node built-ins remain external. No node_modules or dependency installation is needed on the server.

Text
dist/
  server.js       bundled server
  package.json    ESM marker
  public/
    _hum/         client runtime, island chunks and styles
    ...           the project's public files

The directory can be renamed or relocated: asset URLs use /_hum/, independent of its name. Serve only its public/ tree as static files. Include any additional application resources loaded through runtime-computed paths too. The Cloudflare template already enables standalone mode and configures an asset binding for public/.

When dependencies need their installed files

Some dependencies cannot be bundled into a standalone server. Native addons need platform binaries, and some packages read resources or resolve modules relative to their installed package directory. For these applications, omit standalone or set it to false. This is Hum's default build mode.

The non-standalone build preserves server modules and keeps npm dependencies external. Deploy it alongside production dependencies installed from the application's manifest and lockfile. Node's normal dependency resolution keeps native addons and package resources available.

Install production dependencies

For a project whose dependencies are available from a registry, build locally with development dependencies installed. For example, using npm:

Shell
npm ci
npm run build

Copy the complete dist/ build, the application's original package.json, its matching package-lock.jsonand any runtime resources to a deployment directory. Keep the original manifest and lockfile at the deployment root, next to dist/. Keep Hum's generated dist/package.json in place.

Text
deployment/
  package.json         the application's original manifest
  package-lock.json    matching lockfile
  dist/                the complete Hum build
    server.js
    package.json       Hum's ESM marker
    public/

On the server, install production dependencies and start the app from the deployment root:

Shell
# On the server, from the deployment directory:
npm ci --omit=dev
node dist/server.js

Keep runtime packages in dependencies. If you use another package manager, include its matching lockfile and use its production install command. Install native dependencies on the deployment OS and architecture. Node resolves dependencies from the root's node_modules; expose only dist/public/ as static files.

Monorepos with local package dependencies

Monorepos can use npm, Yarn, pnpm or other build and package management tools; Hum does not require a particular one. If all production dependencies are registry-installable, the ordinary deployment above still applies. Local references such as workspace:, file: or link: need extra handling: deploying only the app may leave dependency links pointing to the source checkout.

Build the local packages first. Then either publish/package them for the deployment install, or use your tooling to assemble an independent directory containing the app and its production dependency graph. Include each package's compiled outputs and runtime resources, and check that dependency links resolve within the deployment.

Example: pnpm

For a project using pnpm workspaces, pnpm deploy --prod can assemble that directory without publishing the local packages. This example uses the Hum repository's hum-docs app and was tested with pnpm 11.20.0.

Merge these settings into the workspace root's pnpm-workspace.yaml. Injection lets deployment copy workspace packages instead of linking back to the checkout. Synchronizing after each build script refreshes their compiled outputs; use your actual build script names if they differ.

YAML
# pnpm-workspace.yaml — merge with your existing settings
injectWorkspacePackages: true
syncInjectedDepsAfterScripts:
  - build

Include dist in the application package's files list, plus any resources it reads at runtime. Each workspace dependency must also include its compiled outputs in its own package files.

JSON
{
  "files": ["dist"]
}

Keep packages needed at runtime in dependencies; deployment with --prod excludes development dependencies. Add a script to the workspace root's package.json. This example uses the Hum repository's hum-docs package and existing root build script, which builds workspace dependencies before the app. Substitute your application's package name and build command.

JSON
{
  "scripts": {
    "deploy:docs": "pnpm build && pnpm --filter hum-docs deploy --prod ../hum-deploy"
  }
}

After enabling injection, install once to update the lockfile, then build, deploy and start the result. Choose a new or empty destination directory for each deployment.

Shell
pnpm install --no-frozen-lockfile
pnpm deploy:docs
node ../hum-deploy/dist/server.js

Commit the updated lockfile. Subsequent CI runs can use the frozen lockfile:

Shell
pnpm install --frozen-lockfile
pnpm deploy:docs

Use the modern deploy implementation with injection enabled. In the tested workspace, --legacy left workspace dependency links pointing to the source checkout, making that output unsuitable for independent deployment.

Run the deployed directory

Text
hum-deploy/
  package.json
  node_modules/       production dependencies, including workspace packages
  dist/
    server.js
    app.js
    routes/
    _generated/
    package.json      ESM marker
    public/           the only directory to serve as static files

Transfer the entire directory, including node_modules, and preserve its internal links. The installed dependencies are ready to run; no server-side install is needed. The application manifest may still contain workspace: specifiers. Build native dependencies on the deployment OS and architecture.

Hum's generated dist/package.json only marks ESM and does not copy dependencies. Node resolves them from the deployed parent directory's node_modules. Set PORT to change the example server's default port of 3000.

Configure a reverse proxy or static asset service to expose only dist/public/. Server modules, manifests and dependencies must remain outside the public HTTP tree.