Serverless Framework v3 to v4: Deadlines, Licensing and Upgrade Steps

Serverless Framework v3 reached end of support on 1 January 2025. It gets no security fixes, bug fixes or new features, and it still bundles aws-sdk v2, which AWS stopped supporting in September 2025. Version 4 is the direct way forward.

Changing frameworkVersion from 3 to 4 is one line. The rest of the work is the licence key, the build step, the plugins and the pipeline, and confirming that the first v4 deploy replaces no resource. This post covers what v4 costs, what changes, the one-time setup, the steps to move a service safely, and what changes for developers day to day.

How much time you have

v3 has no shutdown date. It still installs and deploys, and it will even deploy nodejs24.x, because its runtime check only gives a warning. The deadlines that matter come from AWS’s runtime deprecation schedule:

Runtime AWS blocks creating functions AWS blocks updating functions
nodejs16.x, nodejs18.x, nodejs20.x 29 July 2027 31 August 2027
nodejs22.x 1 June 2027 1 July 2027
python3.8 to python3.11 29 July 2027 31 August 2027
nodejs24.x 1 June 2028 1 July 2028
python3.12 30 November 2028 10 January 2029

What the two blocks mean:

  • Create block: you can’t create a function on that runtime. Deploying a new stage or region fails, and so does any change that makes CloudFormation replace a function.
  • Update block: you can’t change the code or configuration of existing functions. The only change still allowed is moving to a supported runtime.
  • Existing functions keep running after both blocks, but AWS no longer patches them.

Node.js 22 is blocked two months before Node.js 18 and 20, so skip it and go straight to nodejs24.x. AWS has moved these dates before, so check the Lambda runtimes page when you plan.

These dates also catch v3 itself. For some features, v3 adds a small helper Lambda to your stack, and in the final v3 release (3.40.0) that helper always runs on nodejs16.x. No setting changes it. v3 uses the helper for:

  • API Gateway logs (provider.logs.restApi or provider.logs.websocket), unless provider.logs.restApi.roleManagedExternally: true is set;
  • S3 events with existing: true;
  • Cognito events with existing: true;
  • EventBridge events with useCloudFormation: false.

Every v3 deploy updates the helper. So for services that use any of these features, v3 can’t create new stages from 29 July 2027 and can’t deploy at all from 31 August 2027, even if your own functions are on nodejs24.x. v4 (4.43.0) runs the same helper on nodejs24.x.

The order is: fix runtimes and data protection on v3 first, then upgrade to v4 one service at a time, and finish before 29 July 2027.

What v4 costs

  • It is free for organisations(projects) with less than $2M in annual revenue. There is no form and no check: if you qualify, you simply don’t subscribe. Non-profit, government and academic organisations are excluded, and so are subsidiaries more than 75% owned by a parent above $2M.
  • Above $2M you pay in credits. One credit is one service, in one stage, in one region, deployed for more than 10 days in a month. Pay-as-you-go costs $4 per credit. Subscribe from the Dashboard’s billing page or through AWS Marketplace. The Customer Agreement says 5 days, so if you sign an Order Form, put 10 days in it.
  • Free still needs an account. Even at $0, you need a Serverless organisation, and every command needs a licence key or a signed-in session.
  • Ignore the “2 free credits” banner. The banner in the Dashboard is about Dashboard features such as traces and metrics. CLI deploys stay free under $2M, so don’t subscribe because of it.
  • If you deploy for clients, the licence follows the client’s revenue. Each client should own its own Serverless organisation. Never buy on your own account and bill the client for it, because that makes you the licensee and your revenue sets the price.

What actually changes in v4

  • Every command needs authentication. This covers deploy, package and local commands such as serverless offline, for free organisations too. Authentication means a licence key or a signed-in session. Set it up once, as described below, and developers never handle it.
  • The npm package only downloads the framework. The real binary comes from install.serverless.com. Your lock file does not pin the version; frameworkVersion does.
  • esbuild is built in. v4 can build and bundle your code itself, which conflicts with build plugins such as serverless-esbuild or serverless-webpack.
  • serverless package now needs valid AWS credentials. v3 didn’t.
  • The default deployment method is now direct. That means no change sets unless you ask for them.
  • Compose is built in. The separate @serverless/compose package and --max-concurrency no longer exist.
  • Several popular plugins are now part of v4 itself (see step 4 below).

Step 0: Prepare on v3

Do each of these as its own change, deployed with v3:

  • Move functions to nodejs24.x, or to python3.12 or later.
  • Add DeletionPolicy: Retain and UpdateReplacePolicy: Retain to every table, bucket, queue and user pool. Include a small Metadata change in the same deploy, or CloudFormation reports “No updates to perform”.
  • Turn on point-in-time recovery for each table and take an on-demand backup.
  • Remove plugins that are installed but not listed under plugins:.
  • Stop CI from printing credentials or parameter values in its logs.
  • Allow build agents to reach install.serverless.com and core.serverless.com over HTTPS.

A note on the retain policies. The common fear is that “v4 will replace our DynamoDB tables.” It won’t: v4 keeps v3’s naming rules, and tables are written by hand under resources:. The real risk is often already in the template: tables with no retain policies at all. That risk exists today, on v3. Also, DeletionProtectionEnabled alone does not stop a replacement. CloudFormation creates a new, empty table, the application starts using it, and the deploy reports success.

One-time setup: the organisation and the licence key

Do this once per company. If you deploy for clients, do it once per client, in the client’s own organisation and AWS accounts.

Create the organisation. Sign up at app.serverless.com and create your organisation. Use a company-owned login, not a personal one, so the organisation doesn’t depend on one person. The organisation is the account that all usage is counted against. Its name, as shown in the Dashboard, is what you pass as --org to the usage commands later.

Create a licence key. An admin of the organisation creates it in the Dashboard under Settings → License Keys. You can create as many keys as you like; one is enough to start.

Store the key in AWS SSM Parameter Store. v4 finds it automatically only if all of these are true:

  • the parameter name is exactly /serverless-framework/license-key;
  • it is in the same AWS account and region as the deployment. v4 reads it with the deployment’s own credentials, profile and region, so create it in every account and every region you deploy to;
  • nothing else supplies a key first. A licenseKey in serverless.yml, the SERVERLESS_LICENSE_KEY or SERVERLESS_ACCESS_KEY environment variable, or a signed-in session (serverless login) all take priority over SSM.
read -rs LICENSE_KEY    # paste the key; it is not shown or saved in shell history
aws ssm put-parameter \
  --name "/serverless-framework/license-key" \
  --type SecureString \
  --value "$LICENSE_KEY" \
  --region <region> --overwrite

The deployment role, and every developer who deploys, needs ssm:GetParameter on this parameter, plus kms:Decrypt if you encrypt it with your own KMS key.

To keep the key under a different name, point to it from the config: licenseKey: ${ssm:/your/path}. Never paste the key itself into serverless.yml.

Upgrading a service, step by step

Upgrade one service at a time, on a non-production stage first.

1. Save the v3 baseline. Package with v3 and keep the output. It contains resolved secrets, so don’t commit it.

npx serverless@3 package --stage <stage>
cp -r .serverless v3

Use serverless@3 explicitly. Without the @3, npx can download the latest release, which is v4, and your baseline would be wrong.

2. Update serverless.yml.

 service: my-service
-frameworkVersion: "3"
+frameworkVersion: "4.43.0"
 provider:
   name: aws
+  deploymentMethod: changesets
+build:
+  esbuild: false    # only if a plugin or script already builds your code

Pin an exact version, and keep the quotes.

3. Update the pipeline. Add v4 to the project (npm install --save-dev serverless@4), then:

-npm i -g serverless@3
-npm i -g @serverless/compose
-serverless deploy --stage qa --max-concurrency 5
+npm ci
+npx serverless deploy --stage qa

The pipeline’s AWS role reads the key from SSM, just as a developer does. No extra pipeline secret is needed.

4. Update the plugins.

Plugin Action
serverless-plugin-aws-alerts, serverless-python-requirements, serverless-appsync-plugin, serverless-prune-plugin Remove: now built into v4
serverless-offline Upgrade to version 14
serverless-s3-sync Replace: deprecated and no longer maintained
serverless-esbuild, serverless-webpack, serverless-plugin-typescript Keep only with build.esbuild: false
serverless-package-external, serverless-plugin-canary-deployments, serverless-plugin-ifelse, serverless-plugin-scripts Abandoned: test on a non-production stage that each still does its job

5. Package with v4 and compare logical IDs. Run serverless logout first, and use the AWS credentials for the stage’s account. This is the first v4 run, so it also tests the licence key: if v4 asks you to sign in, it did not find the key in SSM.

npx serverless package --stage <stage>
cp -r .serverless v4
list() {
  jq -r '.Resources | to_entries[]
    | select(.value.Type != "AWS::Lambda::Version" and .value.Type != "AWS::ApiGateway::Deployment")
    | "\(.key) \(.value.Type)"' "$1" | sort
}
diff <(list v3/cloudformation-template-update-stack.json) \
     <(list v4/cloudformation-template-update-stack.json)

This shows the tables are safe instead of assuming it. If the diff prints anything, stop.

Also compare the .zip sizes in v3/ and v4/. A large difference means the code is now being built or bundled differently.

6. Review the change set before you deploy. Create it, read it, then delete it. Don’t execute it. The stack is usually named <service>-<stage>. Find its deployment bucket first:

aws cloudformation describe-stack-resource --stack-name <stack> \
  --logical-resource-id ServerlessDeploymentBucket \
  --query StackResourceDetail.PhysicalResourceId --output text

If the service sets provider.deploymentBucket, use that bucket instead. Then:

aws s3 cp v4/cloudformation-template-update-stack.json s3://<deployment bucket>/review/template.json
aws cloudformation create-change-set --stack-name <stack> --change-set-name v4-review \
  --template-url https://<deployment bucket>.s3.<region>.amazonaws.com/review/template.json \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
aws cloudformation describe-change-set --stack-name <stack> --change-set-name v4-review \
  --query 'Changes[].ResourceChange.[Action,LogicalResourceId,ResourceType,Replacement]' --output table
aws cloudformation delete-change-set --stack-name <stack> --change-set-name v4-review

Stop if a table, bucket, queue, user pool, API or log group shows Remove, or shows Replacement as True or Conditional.

7. Deploy to the non-production stage with npx serverless deploy --stage <stage>. Then call every endpoint and invoke each function once.

8. Promote stage by stage, repeating steps 5 to 7 for each stage.

Day to day for developers

Once the key is in SSM, a developer’s routine barely changes:

git clone <repo> && cd <repo>
npm ci
npx serverless deploy --stage dev

There is no sign-in and no key to copy. v4 reads the licence key from SSM using the developer’s own AWS credentials, the same credentials it already uses to deploy. A few things are different:

  • Every command uses the key, not only deploy. package, info, logs, invoke and local commands such as serverless offline all check for it. They work as long as the developer’s AWS profile and region point at an account that holds the parameter.
  • If v4 asks you to sign in, don’t. It means v4 didn’t find the key. Check your AWS profile and region instead.
  • Run the project’s install, not a global one. npx serverless runs the copy installed in the project, which follows frameworkVersion. An old global v3 sls refuses to deploy a service pinned to v4. The first run downloads the framework, so it needs internet access.
  • Don’t sign in with a personal account. A signed-in session takes priority over the SSM key, so the deploy is recorded against the developer’s personal organisation instead of yours. Anyone who has ever run serverless login should run serverless logout.
  • Developers never need to see the key. AWS IAM controls who can read it. When someone leaves, removing their AWS access removes their access to the key too, and there is nothing to collect or rotate.
  • Local commands cost nothing. Billing counts deployed services: one service, in one stage, in one region, deployed for more than 10 days in a month. Running serverless offline or package adds nothing. A personal stage that stays deployed for more than 10 days does count above the free tier, so remove personal stages when you finish with them.

Treat the licence key as a secret. Anyone who has it can run Serverless Framework under your organisation, and their deploys count towards your usage. Keep it in SSM as a SecureString. Never commit it, and never paste it into chat, tickets or CI logs.

Per-developer keys are possible but rarely needed. Credits are counted per deployed service, not per key, so extra keys don’t change the bill. One key per AWS account in SSM is the simplest setup. If someone does need their own key, create a named key for them in the Dashboard, set it as SERVERLESS_LICENSE_KEY on their machine, and revoke it when they leave.

Things that will catch you out

  • Unquoted frameworkVersion: 4 is ignored, and the framework updates itself. Always quote it.
  • A v4 frameworkVersion also blocks old v3 installs. A global v3 refuses to deploy the service. A v4 devDependency on its own doesn’t stop a global v3.
  • build.esbuild: false and build.esbuild.bundle: false are different. Only the first turns esbuild off and clears the conflict with a build plugin.
  • CI jobs that only package now need AWS credentials.
  • useDotenv: false now turns off all .env loading.
  • Use 4.29.3 or later. Earlier 4.29.x releases have a security flaw (CVE-2025-69256).

Rollback

Revert the upgrade commit, including package.json and the lock file, then deploy with v3: npx serverless@3 deploy --stage <stage>. A failed deploy rolls back on its own.

After the upgrade

  • Run npx serverless@4 usage --org <org> every month, from the first month, even if you pay nothing. It lists the service instances you are billed for. <org> is your organisation’s name in the Dashboard.
  • After deleting a stack by hand, run npx serverless@4 reconcile --org <org> in that AWS account so the vendor stops billing for it.

v4 is not the only way out of v3. If its terms or cost don’t suit your project, you can migrate to AWS SAM without losing data. That path needs a post of its own.

Questions and corrections are welcome in the comments.

1 Like