> ## Documentation Index
> Fetch the complete documentation index at: https://docs.springwinter.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Deploy a Node.js Application on Springwinter

> Deploy a production Node.js application from GitHub to AWS ECS with Springwinter, including Docker, health checks, environment variables, graceful shutdown, logs, and scaling.

A Node.js application fits Springwinter's web server resource when it accepts HTTP traffic and can run in a container. Springwinter builds the image from GitHub, runs it on AWS ECS in your account, and connects it to a public HTTPS endpoint.

*Updated October 9, 2026.*

**The shortest production path is GitHub repository, Dockerfile, health endpoint, environment variables, then Deploy.**

## Prepare the application

Listen on `0.0.0.0` and read the port from `PORT`. Add a lightweight endpoint that does not depend on slow external services.

```js theme={null}
import express from "express";

const app = express();
app.get("/healthz", (_request, response) => response.sendStatus(200));

const server = app.listen(process.env.PORT || 3000, "0.0.0.0");

function shutdown() {
  server.close(() => process.exit(0));
  setTimeout(() => process.exit(1), 8000).unref();
}

process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);
```

Graceful shutdown matters because ECS replaces containers during deployments and maintenance. The process should stop accepting requests, finish active work, and exit before forced termination.

## Add a production Dockerfile

Pin a supported Node.js LTS version. Install dependencies in a build stage and run as a non-root user.

```dockerfile theme={null}
FROM node:24-bookworm-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:24-bookworm-slim
ENV NODE_ENV=production
WORKDIR /app
COPY --from=build --chown=node:node /app ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
```

Use exec-form `CMD` so Node receives signals directly. Do not put secrets in the image.

## Deploy with Springwinter

<Steps>
  <Step title="Connect AWS and GitHub">
    Connect the AWS account that will own the infrastructure, then install the Springwinter GitHub App for the repository.
  </Step>

  <Step title="Create a web server">
    Open a project, click **Add resource**, and choose **Web server**.
  </Step>

  <Step title="Choose source and compute">
    Select the repository and branch. Choose CPU and memory based on measured load, not guesses.
  </Step>

  <Step title="Configure health and environment">
    Set the health path to `/healthz`. Add `NODE_ENV`, application configuration, and service URLs as environment variables.
  </Step>

  <Step title="Deploy and verify">
    Deploy, open the generated HTTPS URL, inspect CloudWatch-backed logs, and confirm CPU, memory, requests, and errors under **Metrics**.
  </Step>
</Steps>

## Production checklist

* Commit lockfiles and use `npm ci` for reproducible builds.
* Keep request handlers stateless; place durable data in a database or S3.
* Send logs to stdout and stderr.
* Set explicit request, database, and outbound HTTP timeouts.
* Test shutdown during active traffic.
* Enable auto-deploy only on the branch that should reach production.
* Use previews for branch-level validation before merging.

## Common deployment failures

A health check fails when the server binds only to localhost, listens on the wrong port, or performs expensive dependency checks. An out-of-memory restart usually means the selected memory is too small or the process has an unbounded cache. A deployment that never exits often runs through a shell wrapper that does not forward `SIGTERM`.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Does Springwinter require a Node.js buildpack?">
    No. A Dockerfile gives you the clearest and most reproducible deployment. Springwinter builds the container from your GitHub source and runs the resulting image on ECS in your AWS account.
  </Accordion>

  <Accordion title="Where should Node.js secrets live?">
    Configure secrets and service URLs as runtime environment variables. Never commit secrets to GitHub or copy them into a Docker image layer.
  </Accordion>

  <Accordion title="Can Springwinter deploy a Node.js monorepo?">
    Yes, when the repository's Dockerfile copies the correct workspace and produces one runnable image. Keep the Docker build context small and make the target service explicit.
  </Accordion>
</AccordionGroup>

## Sources and further reading

* [Official Node.js Docker image](https://github.com/nodejs/docker-node)
* [Node.js Docker best practices](https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md)
* [Springwinter web servers](/deploy/web-servers)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.