You've got Lerna working locally, publishing packages manually like a caveman. Time to automate this before you accidentally publish dev credentials to production like an idiot.
The Authentication Nightmare That Kills Every First Deployment
Your first production deploy fails with npm ERR! 401 Unauthorized
and you spend 4 hours debugging npm tokens. The Artifactory E401 mystery hits everyone - Lerna moved from npm_config__auth
to _authToken
and nobody updated the docs.
GitHub Actions setup that actually works:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: "Configure npm"
run: |
npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN
npm config set registry https://registry.npmjs.org/
Don't use npm_config__auth
- it's deprecated and will silently fail in ways that waste your entire Tuesday. The authentication token setup needs to be _authToken
or you're debugging phantom auth errors.
Docker Production Builds That Don't Suck
Building Docker images in a monorepo is where most teams fuck up caching. You change one comment in Package A and suddenly Package B rebuilds from scratch, because your Dockerfile copies the entire workspace like an amateur.
The problem: Standard Docker builds treat monorepos like a single codebase. Change anything, rebuild everything. Your build takes 15 minutes when it should take 2.
Multi-stage builds that work:
## Stage 1: Install all dependencies
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json lerna.json ./
COPY packages/*/package*.json ./packages/
RUN npm ci --only=production
## Stage 2: Build specific package
FROM deps AS build
COPY packages/api ./packages/api
RUN npx lerna run build --scope=@company/api
This uses Docker BuildKit to cache dependencies so you don't rebuild everything when you change one comment. Change your API code, only the API rebuilds. The TurboRepo Docker guide has more examples.
Package Publishing Order Hell
We fucked up the publishing order once and got like 30-45 seconds of broken installs - might've been a full minute, felt like forever when Slack was exploding with complaints.
The publishing sequence that breaks everything:
- Update
@company/utils
from 1.2.0 to 1.3.0 - Update
@company/ui
to depend on@company/utils@^1.3.0
- Publish
@company/ui@2.1.0
first (WRONG) - Users install UI 2.1.0, get dependency error for utils 1.3.0
- Your phone rings at 11pm
Lerna handles this automatically with dependency topology sorting, but only if you configure it right:
{
"version": "independent",
"npmClient": "npm",
"command": {
"publish": {
"conventionalCommits": true,
"message": "chore(release): publish",
"registry": "https://registry.npmjs.org"
}
}
}
The lerna publish
command calculates the dependency graph and publishes in order. Package A depends on Package B? Lerna publishes B first. This is the main reason you use Lerna instead of manual npm publish.
Environment-Specific Configuration Without Hardcoding
Your app needs different configs for staging vs prod, but hardcoding environment variables in Docker images is how you leak API keys to customers.
Use build args and runtime environment injection:
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
## Don't copy .env files into images
COPY --exclude=*.env* . .
Configure secrets at deploy time, not build time. The 12-factor app methodology covers this in detail. Your CI should inject secrets as environment variables, never commit them to images.
Monitoring Deployments Without Going Insane
You publish 8 packages at once. Which one broke production? Without proper monitoring, you're grep'ing logs at 2am trying to figure out if the error came from @company/auth@1.2.3
or @company/api@2.1.1
.
Tag deployments in your monitoring:
- Use semantic versioning tags for release tracking
- Conventional commits for automated changelog generation
- Monitor package-specific error rates with tools like Sentry or DataDog
Lerna generates changelogs automatically if you use conventional commits. The output tells you exactly what changed in each package, which helps track down issues. This is why teams enforce commit message formats - not bureaucracy, but debugging sanity.
When package publishing fails mid-process, you end up with some packages published and others stuck. The lerna publish from-git command recovers from partial failures by reading git tags to determine what needs publishing.