Skip to content
For the complete Netlify documentation index, see llms.txt. Markdown versions of this page are available by appending .md to the URL.

Unlimited seats on Netlify Pro for $20/month → Learn more 👥

Trigger functions on events

For the complete documentation index, see llms.txt

You can trigger serverless function calls when certain Netlify events happen, like when a deploy completes successfully.

An event-triggered function is built like any other, as described in the get started with functions doc. To subscribe to one or more events, export a default object from your function and add a method for each event you want to handle.

netlify/functions/on-deploy.mts
import type { DeploySucceededEvent, DeployFailedEvent } from "@netlify/functions"
export default {
deploySucceeded(event: DeploySucceededEvent) {
console.log(`Deploy ${event.deploy.id} succeeded for ${event.site.name}`)
},
deployFailed(event: DeployFailedEvent) {
console.log(`Deploy ${event.deploy.id} failed: ${event.deploy.errorMessage}`)
},
}

A single function can subscribe to multiple events by declaring the corresponding handlers, and multiple functions can declare a handler for the same event — both will run.

The arguments and return values of all event handlers are fully typed, making them easier to work with by humans and their IDEs, as well as by AI coding agents.

Before the handler syntax above, functions subscribed to events by matching the file name to the event name.

This convention is still fully supported and continues to work for all the events listed below, but new functions should prefer the typed handler syntax — it's clearer to read, supports multiple events from a single function, and gives you full type checking on the event payload.

For example, the following file would run on every successful deploy:

netlify/functions/deploy-succeeded.mts
export default async (req: Request) => {
const { payload } = await req.json()
console.log(`Deploy ${payload.id} shipped`)
}

Every event handler is fully typed. Import the corresponding event type from @netlify/functions and TypeScript will validate the event shape and your return value at the call site.

These handlers fire across the deploy lifecycle. All share the same event shape and return contract.

| Handler | Event type | Triggered when | |---|---|---| | deployBuilding | DeployBuildingEvent | Netlify starts building a site for deployment | | deploySucceeded | DeploySucceededEvent | Netlify finishes deploying a site | | deployFailed | DeployFailedEvent | A deploy does not complete | | deployDeleted | DeployDeletedEvent | A deploy is deleted | | deployLocked | DeployLockedEvent | A deploy is locked in production and Netlify stops autopublishing deploys | | deployUnlocked | DeployUnlockedEvent | A deploy is unlocked from production and Netlify resumes autopublishing deploys |

Return value: void or Promise<void>. The return value is not used by the platform.

The event has two properties, deploy and site:

An object describing the deploy.

  • id: unique deploy ID
  • siteId: ID of the site this deploy belongs to
  • buildId: ID of the build that produced this deploy, or null if the deploy was created without a build (for example, a direct CLI upload)
  • state: current state of the deploy
  • errorMessage: error message if the deploy failed, otherwise null
  • url: primary URL of the deploy
  • sslUrl: HTTPS URL of the deploy
  • permalinkUrl: permalink URL of the deploy
  • adminUrl: Netlify UI URL for the deploy
  • context: deploy context (for example, production, deploy-preview, branch-deploy)
  • branch: Git branch the deploy was built from, or null
  • commitRef: Git commit SHA, or null
  • commitUrl: URL to the commit on the Git provider, or null
  • commitMessage: Git commit message, or null
  • committer: name of the committer, or null
  • title: deploy title (typically the commit message subject), or null
  • createdAt: ISO 8601 timestamp when the deploy was created
  • publishedAt: ISO 8601 timestamp when the deploy was published, or null if it isn't published
  • time: total build time in milliseconds, or null if the deploy didn't go through a build
  • manual: true if the deploy was created manually (for example, a CLI upload), false if it came from a Git push or Netlify build
  • framework: detected framework slug, or null

An object describing the site the deploy belongs to.

  • id: unique site ID
  • name: site name — its Netlify subdomain
  • url: primary site URL
  • adminUrl: Netlify UI URL for the site

These handlers fire across the Identity user lifecycle. On top of running its own logic, each handler can do two things to influence what the platform does next:

  • Deny the action: Call event.deny() from inside the handler to reject the user's request. The platform aborts the lifecycle action and the end user gets a 401. Use this to enforce server-side rules, like blocking signups from disallowed email domains or logins outside a maintenance window.
  • Mutate the user record: Return an object with a user property to apply changes that are then persisted on the user. Use this to attach application-managed metadata, assign roles, or normalize fields the user submitted (lowercased emails, trimmed names, and so on).

userDeleted is notification-only: by the time it fires, there's no action left to deny and no record left to mutate. Every other handler can do both.

| Handler | Event type | Triggered when | Can deny? | Can mutate? | |---|---|---|---|---| | userValidate | UserValidateEvent | A user attempts to sign up, before the account is created. | Yes | Yes | | userSignup | UserSignupEvent | A user completes signup. | Yes | Yes | | userLogin | UserLoginEvent | A user logs in. | Yes | Yes | | userModified | UserModifiedEvent | A user's profile is updated. | Yes | Yes | | userDeleted | UserDeletedEvent | A user is deleted. | No | No |

Return value: an object with a user property to apply mutations to the user record, or undefined/void to pass the user through unchanged. userDeleted always returns undefined/void.

Denying the action: in userValidate, userSignup, userLogin, or userModified, call event.deny() to reject the request. The end user gets a 401. If multiple functions subscribe to the same event, the first to call event.deny() aborts the chain. See Identity event functions for full examples.

An object describing the affected user. Only id is guaranteed to be present — the rest of the fields are optional and may be omitted depending on the user's provider and the lifecycle stage.

  • id: unique user ID
  • email: user's email address
  • confirmedAt: ISO 8601 timestamp when the user's email was confirmed
  • createdAt: ISO 8601 timestamp when the user was created
  • updatedAt: ISO 8601 timestamp of the most recent profile update
  • role: the user's role
  • provider: the identity provider the user authenticated with (for example, email, google, github)
  • name: display name
  • pictureUrl: URL of the user's profile picture
  • roles: array of role names assigned to the user
  • invitedAt: ISO 8601 timestamp the user was invited
  • confirmationSentAt: ISO 8601 timestamp the confirmation email was last sent
  • recoverySentAt: ISO 8601 timestamp the password recovery email was last sent
  • pendingEmail: email address pending confirmation, during an email change
  • emailChangeSentAt: ISO 8601 timestamp the email-change confirmation was sent
  • lastSignInAt: ISO 8601 timestamp of the user's most recent sign-in
  • userMetadata: a free-form object containing user-supplied metadata
  • appMetadata: a free-form object containing application-managed metadata. Use this for fields the user can't set themselves, such as role assignments or custom claims

This handler fires when a form submission is verified.

| Handler | Event type | Triggered when | |---|---|---| | formSubmitted | FormSubmittedEvent | A form submission is verified for your site. |

Return value: void or Promise<void>. The return value is not used by the platform.

An object keyed by field name with string values, capturing the verified submission exactly as received.

To prevent external requests to event functions, Netlify generates a JSON web signature (JWS) for each event triggered by our platform, and verifies that the signature is correct before invoking an associated event function.