Project Setup Basics
9 examples to get you started with Project Setup - 7 basic and 2 intermediate.
Prerequisites
- Node.js 24.18.0 and npm 10+.
- TypeScript 5.6+:
npm init -y && npm install -D typescript@5.6 tsx @types/node. - Git initialized:
git init && git add . && git commit -m "init".
Basic Examples
1. Standard API Service Layout
Separate source, tests, and config at the repo root for clarity.
billing-api/
src/
server.ts
routes/
services/
test/
health.test.ts
package.json
tsconfig.json
Dockerfile
.gitignore
src/holds runtime TypeScript;test/mirrors domain folders.- Config files live at root so tooling discovers them without extra flags.
- One deployable per repo unless you adopt an explicit monorepo layout.
Related: Scaffolding APIs - bootstrap from templates
2. package.json Scripts for Dev and Prod
Wire the daily commands every contributor and CI job runs.
{
"type": "module",
"scripts": {
"dev": "tsx watch src/server.ts",
"build": "tsc -p tsconfig.build.json",
"start": "node dist/server.js",
"test": "node --import tsx --test",
"typecheck": "tsc --noEmit"
}
}devfor local iteration;startruns compiled output in production.typecheckfails fast without emitting files.- Scripts are the contract - document them in README.
3. TypeScript Config Split
Use separate configs for build output vs editor/CI typecheck.
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noEmit": true,
"rootDir": ".",
"types": ["node"]
},
"include": ["src", "test"]
}// tsconfig.build.json
{
"extends": "./tsconfig.json",
"compilerOptions": { "noEmit": false, "outDir": "dist", "rootDir": "src" },
"include": ["src"]
}NodeNextmatches Node 24 ESM resolution.- Build config excludes tests from production
dist/.
4. Environment Files and Gitignore
Keep secrets out of git; document required variables.
# .gitignore
node_modules/
dist/
.env
.env.local
coverage/
# .env.example (committed)
PORT=3000
DATABASE_URL=postgres://localhost:5432/billing
LOG_LEVEL=info
- Commit
.env.example, never.env. - Load and validate env at startup (Zod schema in a later service hardening step).
5. Minimal Dockerfile
Multi-stage build: install, compile, run slim runtime image.
FROM node:24.18.0-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:24.18.0-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]- Pin Node patch in
FROMto matchengines. - Copy lockfile before source for Docker layer caching.
6. Health Check Entry Point
Every service exposes a liveness route from day one.
// src/server.ts
import express from "express";
const app = express();
app.get("/health", (_req, res) => {
res.json({ status: "ok" });
});
const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`listening on ${port}`));/healthis load balancer and orchestrator friendly.- Keep it free of database calls for basic liveness (readiness can be separate).
7. README Onboarding Block
New hires run three commands and get a green test.
## Quick start
npm ci
cp .env.example .env
npm run dev
## Checks
npm run typecheck
npm test- README is part of project setup - not an afterthought.
- Match commands to
package.jsonscripts exactly.
Intermediate Examples
8. Colocated vs Separate Test Folders
Pick one convention per repo and enforce it.
# Option A: top-level test/ (shown above)
test/routes/health.test.ts
# Option B: colocated
src/routes/health.test.ts
- Top-level
test/keepsdist/clean without extra exclude rules. - Colocated tests sit beside modules - good for unit-heavy domains.
- Never mix both patterns in one service.
Related: Testing Basics - pyramid for APIs
9. Monorepo vs Single-Service Repo
Start single-service; split when boundaries are clear.
| Layout | Choose when |
|---|---|
Single repo / single src/ | One deployable API, team < 8 |
apps/ + packages/ workspaces | 2+ deployables sharing types/libs |
- Premature monorepos tax every PR with coordination overhead.
- Extract shared code when the third service copies the same module.
Related: Multi-Service Monorepo - boundary rules
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.