Build extensions
Customize how your project is built and deployed to Trigger.dev with build extensions
Build extension allow you to hook into the build system and customize the build process or the resulting bundle and container image (in the case of deploying). See our trigger.config.ts reference for more information on how to install and use our built-in extensions. Build extensions can do the following:
- Add additional files to the build
- Add dependencies to the list of externals
- Add esbuild plugins
- Add additional npm dependencies
- Add additional system packages to the image build container
- Add commands to run in the image build container
- Add environment variables to the image build container
- Sync environment variables to your Trigger.dev project
Creating a build extension
Build extensions are added to your trigger.config.ts
file, with a required name
and optional build hook functions. Here’s a simple example of a build extension that just logs a message when the build starts:
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
onBuildStart: async (context) => {
console.log("Build starting!");
},
},
],
},
});
You can also extract that out into a function instead of defining it inline, in which case you will need to import the BuildExtension
type from the @trigger.dev/build
package:
You’ll need to add the @trigger.dev/build
package to your devDependencies
before the below
code will work. Make sure it’s version matches that of the installed @trigger.dev/sdk
package.
import { defineConfig } from "@trigger.dev/sdk/v3";
import { BuildExtension } from "@trigger.dev/build";
export default defineConfig({
project: "my-project",
build: {
extensions: [myExtension()],
},
});
function myExtension(): BuildExtension {
return {
name: "my-extension",
onBuildStart: async (context) => {
console.log("Build starting!");
},
};
}
Build hooks
externalsForTarget
This allows the extension to add additional dependencies to the list of externals for the build. This is useful for dependencies that are not included in the bundle, but are expected to be available at runtime.
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
externalsForTarget: async (target) => {
return ["my-dependency"];
},
},
],
},
});
onBuildStart
This hook runs before the build starts. It receives the BuildContext
object as an argument.
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
onBuildStart: async (context) => {
console.log("Build starting!");
},
},
],
},
});
If you want to add an esbuild plugin, you must do so in the onBuildStart
hook. Here’s an example of adding a custom esbuild plugin:
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
onBuildStart: async (context) => {
context.registerPlugin({
name: "my-plugin",
setup(build) {
build.onLoad({ filter: /.*/, namespace: "file" }, async (args) => {
return {
contents: "console.log('Hello, world!')",
loader: "js",
};
});
},
});
},
},
],
},
});
You can use the BuildContext.target
property to determine if the build is for dev
or deploy
:
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
onBuildStart: async (context) => {
if (context.target === "dev") {
console.log("Building for dev");
} else {
console.log("Building for deploy");
}
},
},
],
},
});
onBuildComplete
This hook runs after the build completes. It receives the BuildContext
object and a BuildManifest
object as arguments. This is where you can add in one or more BuildLayer
’s to the context.
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "my-project",
build: {
extensions: [
{
name: "my-extension",
onBuildComplete: async (context, manifest) => {
context.addLayer({
id: "more-dependencies",
dependencies,
});
},
},
],
},
});
See the addLayer documentation for more information on how to use addLayer
.
BuildTarget
Can either be dev
or deploy
, matching the CLI command name that is being run.
npx trigger.dev@latest dev # BuildTarget is "dev"
npx trigger.dev@latest deploy # BuildTarget is "deploy"
BuildContext
addLayer()
The layer to add to the build context. See the BuildLayer documentation for more information.
registerPlugin()
The esbuild plugin to register.
resolvePath()
Resolves a path relative to the project’s working directory.
The path to resolve.
const resolvedPath = context.resolvePath("my-other-dependency");
properties
The target of the build, either dev
or deploy
.
A logger object that can be used to log messages to the console.
BuildLayer
A unique identifier for the layer.
An array of commands to run in the image build container.
commands: ["echo 'Hello, world!'"];
These commands are run after packages have been installed and the code copied into the container in the “build” stage of the Dockerfile. This means you cannot install system packages in these commands because they won’t be available in the final stage. To do that, please use the pkgs
property of the image
object.
An object of dependencies to add to the build. The key is the package name and the value is the version.
dependencies: {
"my-dependency": "^1.0.0",
};
examples
Add a command that will echo the value of an environment variable:
context.addLayer({
id: "my-layer",
commands: [`echo $MY_ENV_VAR`],
build: {
env: {
MY_ENV_VAR: "Hello, world!",
},
},
});
Troubleshooting
When creating a build extension, you may run into issues with the build process. One thing that can help is turning on debug
logging when running either dev
or deploy
:
npx trigger.dev@latest dev --log-level debug
npx trigger.dev@latest deploy --log-level debug
Another helpful tool is the --dry-run
flag on the deploy
command, which will bundle your project and generate the Containerfile (e.g. the Dockerfile) without actually deploying it. This can help you see what the final image will look like and debug any issues with the build process.
npx trigger.dev@latest deploy --dry-run
You should also take a look at our built in extensions for inspiration on how to create your own. You can find them in in the source code here.
Was this page helpful?