Most repos get their README, CI and Dockerfile "later," and later turns into never. Here's a short checklist I run through when I start a new Node project. Each step takes a minute or two.
1. Pin your Node version and lock your dependencies
echo "20" > .nvmrc
npm init -y
npm install # creates package-lock.json, commit it
Add an engines field so mismatches show up early:
"engines": { "node": ">=20" }
2. A .gitignore you won't have to fix later
node_modules/
dist/
.env
.env.*
!.env.example
coverage/
Commit a .env.example with placeholder keys so new contributors know which variables to set.
3. A README skeleton
A README only needs to answer a few questions. Start with headings and fill them in as you go:
# project-name
One sentence: what this does and who it's for.
## Quick start
npm ci
cp .env.example .env
npm run dev
## Scripts
| Command | What it does |
|-----------------|---------------------|
| `npm test` | Run tests |
| `npm run build` | Build to `./dist` |
## Configuration
List each env var and its default.
## Contributing
See CONTRIBUTING.md.
## License
MIT
The "Quick start" section matters most. If someone can't run your project from those three lines, fix the project or fix the lines.
4. CI on every push and PR
Save this as .github/workflows/ci.yml:
name: CI
on: [push, pull_request]
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm run lint --if-present
- run: npm test --if-present
- run: npm run build --if-present
A few details: --if-present keeps CI green before you've written a lint or test script. concurrency cancels the old run when you push again. contents: read limits the token to what CI needs.
5. A multi-stage Dockerfile
Build in one stage, ship only what runs:
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
And a .dockerignore, so you don't copy node_modules or secrets into the build context:
node_modules
.git
.env*
dist
Running as the non-root node user is a one-line change that's easy to forget.
6. The small repo files
-
.github/dependabot.ymlfor weekly dependency PRs:
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule: { interval: weekly }
-
.github/pull_request_template.mdwith a short "What / Why / How to test" list. -
CONTRIBUTING.mdandSECURITY.md, even if each is only a few lines. GitHub links them automatically.
The checklist
- [ ]
.nvmrc,engines, committed lockfile - [ ]
.gitignore+.env.example - [ ] README with a working Quick start
- [ ] CI workflow on push and PR
- [ ] Multi-stage Dockerfile +
.dockerignore - [ ] Dependabot, PR template, CONTRIBUTING, SECURITY
If you'd rather not write all of this by hand, I made the ShipKit GitHub Actions Starter Pack. It has 15 workflows (Node, Python and Go CI, Docker to GHCR, semver releases, deploys to Pages, Vercel and Fly, CodeQL and more) plus a repo template set: README, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, a PR template, issue templates, dependabot.yml and labeler.yml: https://8686702537545.gumroad.com/l/clhec?ref=devto-third
Last day: both packs are $9 each with code SHIPKIT9 until tonight, Thursday, Oct 15 at 11:59 PM CT. After that they're $15.
For the Docker side, the Docker & Dev Container Starter Pack ($15, or $9 with SHIPKIT9 today) has Dockerfiles for Node, Python, Go and static sites, three Compose stacks with healthchecks, and dev container configs: https://8686702537545.gumroad.com/l/bafiks?ref=devto-third
Want both? The ShipKit Complete bundle has both packs for $16 (SHIPKIT9 doesn't apply): https://8686702537545.gumroad.com/l/whlyio?ref=devto-third
If your app uses Postgres, Redis, MySQL or MongoDB with Docker Compose, there's also a free generator that writes the healthcheck and depends_on: condition: service_healthy block for you: https://8686702537545.gumroad.com/l/cumhuh?ref=devto-third (free, enter $0; it asks for an email). The snippets are starting points, so check them against your own setup.
Disclosure: I make ShipKit, which sells this pack.
Top comments (0)