Serverless Framework V3 is unmaintained, and its plugin ecosystem is decaying around it. V4 (May 2024) is the supported line, and upgrading is the most common piece of work we do for clients in 2026. This is the procedure we follow, written for a typical Node.js service on AWS. Budget half a day for a simple service and a week for a large one with many plugins.
0. Understand what changed
Before touching anything, know the headline differences between V3 and V4:
- Authentication is mandatory. Every
serverlesscommand that touches AWS requires eitherserverless login(interactive) or a license key / access key in the environment. This applies to CI. - Licensing. Free for organizations under $2M in annual revenue; paid, per Service Instance, above it. Read our licensing explainer if that affects you.
- AWS only. V4 removed support for other cloud providers. If your
serverless.ymltargets Azure or Google Cloud, V4 is not an upgrade path. - Built-in TypeScript bundling. V4 bundles TypeScript and JavaScript with esbuild out of the box.
serverless-esbuild,serverless-webpack, andserverless-plugin-typescriptbecome redundant and can conflict. - New variable resolvers and a
stagesblock for per-stage parameters, plusserverless devfor live local development against your deployed stage.
The official reference is the Upgrading to V4 guide. Keep it open.
1. Inventory the service
Record the current state so you can diff against it later:
node --version # Lambda runtime should already be nodejs20.x or nodejs22.x
npx serverless --version # confirm you are on 3.x
npx serverless print --stage prod > /tmp/v3-resolved.yml
npx serverless package --stage prod --package /tmp/v3-package
serverless print resolves every variable and gives you the effective configuration. The package output contains the CloudFormation template V3 would deploy; you will compare V4's template against it in step 6.
List your plugins:
grep -A 20 '^plugins:' serverless.yml
2. Install V4 and authenticate
npm install --save-dev serverless@4
npx serverless --version # 4.x
Authenticate. For a developer laptop:
npx serverless login
For CI and for anyone who prefers not to use the Dashboard, set a license key or access key as an environment variable. The license keys guide explains which one applies to your account:
export SERVERLESS_LICENSE_KEY=... # license-key accounts
# or
export SERVERLESS_ACCESS_KEY=... # Dashboard accounts
Never commit either value. Put it in your CI secret store and in your local .env (ignored by git).
3. Triage plugins
Work through the plugin list with three buckets:
Remove (now built in):
# Before (V3)
plugins:
- serverless-esbuild
- serverless-plugin-typescript
# After (V4): delete them and configure the built-in bundler if needed
build:
esbuild:
bundle: true
minify: true
sourcemap: true
target: node22
exclude:
- '@aws-sdk/*' # already present in the Node 18+ runtimes
If you genuinely need your own bundler for a while, disable the built-in one with build: { esbuild: false } and keep the plugin; do not run both.
Keep (compatible): serverless-offline, serverless-iam-roles-per-function, serverless-prune-plugin, and most plugins that only add CloudFormation resources generally work. Upgrade each to its latest release and check its README for a V4 note.
Replace: serverless-dotenv-plugin is usually unnecessary because V4 honors useDotenv: true. Plugins that relied on V3 internals (custom variable sources, lifecycle hacks) are the ones that break; check their issue trackers for a V4 compatibility thread before assuming.
4. Update serverless.yml
Bump the framework version pin and the runtime:
frameworkVersion: '4'
provider:
name: aws
runtime: nodejs22.x
region: us-east-1
Move stage-specific values into the new stages block. In V3 most teams used a custom map keyed by stage; V4 makes this first-class:
stages:
default:
params:
tableName: orders-${sls:stage}
logLevel: debug
prod:
params:
logLevel: info
functions:
createOrder:
handler: src/orders.create
environment:
TABLE_NAME: ${param:tableName}
LOG_LEVEL: ${param:logLevel}
Check variable syntax that changed behavior. ${env:VAR} now fails hard when VAR is unset unless you supply a default (${env:VAR, 'fallback'}), and ${ssm:...} and ${cf:...} resolve under the credentials V4 is running with. A surprising number of "it worked on V3" failures are variables that silently resolved to empty strings before.
5. Deploy to a fresh stage
Never upgrade in place on production. Deploy to a throwaway stage first:
npx serverless deploy --stage v4check --verbose
Read the output carefully for deprecation warnings. Then exercise the service: invoke functions, hit the API, and run your integration tests against the new stage.
npx serverless invoke --function createOrder --stage v4check --path test/events/create.json
npx serverless logs --function createOrder --stage v4check --tail
6. Diff the CloudFormation templates
This is the step most teams skip and later regret. Package with V4 and compare to the V3 package you saved in step 1:
npx serverless package --stage prod --package /tmp/v4-package
diff <(jq -S . /tmp/v3-package/cloudformation-template-update-stack.json) \
<(jq -S . /tmp/v4-package/cloudformation-template-update-stack.json)
Expect differences in bundling artifacts and hashes. Investigate anything that changes a logical resource ID, a function name, an API Gateway resource, or an IAM statement. A changed logical ID means CloudFormation will replace the resource, which for a DynamoDB table or an S3 bucket is data loss. If you find one, fix the configuration until the ID is stable; do not proceed on the assumption it will be fine.
7. Update CI
Your pipeline needs three things: the V4 package installed, the license or access key in the environment, and AWS credentials. If you are still using long-lived AWS access keys in CI, this is a good moment to switch to OIDC; we cover that in CI/CD for Serverless Framework Apps with GitHub Actions and OIDC. The minimal change:
- run: npm ci
- run: npx serverless deploy --stage ${{ github.ref_name == 'main' && 'prod' || 'staging' }}
env:
SERVERLESS_LICENSE_KEY: ${{ secrets.SERVERLESS_LICENSE_KEY }}
8. Promote and verify
Deploy to staging, then production, with --verbose on, and confirm:
- CloudFormation shows
UPDATE_COMPLETEwith no replaced resources. - Function ARNs and API endpoints are unchanged (
serverless info --stage prod). - Alarms and dashboards still receive metrics (function names are part of metric dimensions).
- Remove the
v4checkstage:npx serverless remove --stage v4check.
What to do if it goes wrong
A failed stack update rolls back automatically. A successful update that replaced a resource does not; that is why step 6 exists. Keep the V3 lockfile on a branch until production has completed at least one full deploy cycle on V4, and keep the serverless print output from step 1 as the record of what the service used to resolve to.
If your estate has dozens of services, or a plugin nobody on the team understands, our V4 upgrade and migration service starts with the same inventory and ends with every stack on a supported footing. Get in touch.