Canva App Scripts

Build and run your app without worrying about the bundler.

@canva/app-scripts(opens in a new tab or window) is the best way to build your Canva App. It replaces multiple dependencies, config files, and build scripts with a single package that provides everything you need to build and run your app. Maintenance is simplified and performance is greatly enhanced.

@canva/app-scripts is the package that powers the canva apps start and canva apps build Canva CLI commands. It's responsible for bundling your app's source code into the single JavaScript file that Canva loads, running your local development server, and extracting translation messages for localization.

The goal of @canva/app-scripts is that you shouldn't have to think about any of this detail. Apps created with the starter kit or a CLI template come with sensible defaults already configured for React, TypeScript, CSS modules, SVGs, and FormatJS i18n, so you can focus on your app's code instead of its build tooling.

If your app has its own webpack.config.ts and a bespoke scripts/start/ runner at its root, it isn't on @canva/app-scripts yet. This is common for apps created from an older snapshot of the starter kit or CLI template. See the migration guide to move onto @canva/app-scripts.

Using app-scripts

You don't call @canva/app-scripts directly; the Canva CLI serves as the interface:

canva apps start

Runs the local development server (see Previewing apps):

canva apps start
SHELL

Terminal output of canva apps start, showing the frontend URL and a link to preview the app

canva apps build

Produces the standalone JavaScript bundle for upload to the Developer Portal (see Bundling apps), and extracts translation messages as part of the same command:

canva apps build
SHELL

Terminal output of canva apps build, showing the app bundle and extracted translations output

By default, @canva/app-scripts bundles with Rsbuild(opens in a new tab or window). For the full set of default values (ports, entry paths, output directories, and the complete Rsbuild/webpack configuration it applies on your behalf), see Configuration reference.

Customizing away from defaults

Most apps need no configuration at all. If you do need to change something, create a canva-app.config.ts file at your project root and export a config object using defineConfig:

// canva-app.config.ts
import { defineConfig } from "@canva/app-scripts";
export default defineConfig({
// your overrides
});
TS

Common reasons to add one:

Your frontend entry isn't the default

Set entry to the correct path (the default is src/index.tsx):

// canva-app.config.ts
import { defineConfig } from "@canva/app-scripts";
export default defineConfig({
entry: "./src/main.tsx",
});
TS

Your app has a backend

Set backend.entry to point at your backend's entry file:

// canva-app.config.ts
import { defineConfig } from "@canva/app-scripts";
export default defineConfig({
backend: {
entry: "./backend/server.ts",
},
});
TS

You need to customize the bundler, or keep using webpack

The config field is your escape hatch: a function that receives the Rsbuild configuration @canva/app-scripts resolved, and returns the configuration to use:

// canva-app.config.ts
import { defineConfig } from "@canva/app-scripts";
export default defineConfig({
config: (config, { mode }) => {
// Tweak the resolved Rsbuild config here, then return it.
return config;
},
});
TS

If you'd rather use webpack instead of Rsbuild, set bundler: "webpack" explicitly. The function then receives a webpack Configuration instead:

// canva-app.config.ts
import { defineConfig } from "@canva/app-scripts";
export default defineConfig({
bundler: "webpack",
config: (config, { mode }) => {
// Tweak the resolved webpack config here, then return it.
return config;
},
});
TS

Next steps

  • See every default value @canva/app-scripts applies, and the full resolved Rsbuild/webpack config objects, in the Configuration reference.
  • See the full programmatic API (build, dev, extractTranslations, defineConfig, and the config types) in the API reference.