Skip to content

[APPS] Support uploading backend functions to app definitions#284

Draft
sdkennedy2 wants to merge 6 commits intomasterfrom
sdkennedy2/apps-backend-functions-upload
Draft

[APPS] Support uploading backend functions to app definitions#284
sdkennedy2 wants to merge 6 commits intomasterfrom
sdkennedy2/apps-backend-functions-upload

Conversation

@sdkennedy2
Copy link
Collaborator

@sdkennedy2 sdkennedy2 commented Mar 10, 2026

Motivation

High code apps need the ability to define backend functions that get bundled and published to the app definition after upload. This enables server-side logic to be co-located with the app's frontend code and automatically deployed as part of the build process.

See RFC: Backend Functions for the full design.

Changes

Added a complete backend functions pipeline that runs during the build:

  1. Discovery — scans a configurable backendDir (default: backend/) for function modules. Supports both single-file (backend/myFunc.ts) and directory (backend/myFunc/index.ts) patterns.

  2. Bundling — each discovered function is bundled with esbuild into a single self-contained file. Everything is inlined with no externals, since the execution environment does not support require or import at runtime. If @datadog/action-catalog is installed, its setExecuteActionImplementation export is forced into the bundle.

  3. Transformation — bundled code is wrapped in the Action Platform script format with a main($) entry point that registers the $.Actions-based executeAction implementation and invokes the function with template-resolved args.

  4. Archive inclusion — transformed functions are written to temp files and included in the upload zip archive alongside frontend assets. Frontend assets are namespaced under a configurable frontendDir (default: frontend/) and backend functions under backend/ within the archive. The archive is uploaded via the existing POST .../upload endpoint — no separate API call is needed.

Shared constants (ACTION_CATALOG_EXPORT_LINE, SET_EXECUTE_ACTION_SNIPPET) are extracted into backend-shared.ts for reuse by the upcoming dev server middleware.

New configuration options:

{
  apps: {
    backendDir: 'backend',   // directory containing backend function modules
    frontendDir: 'frontend', // prefix for frontend assets in the upload archive
  }
}

Design Decisions

Why esbuild as a direct dependency instead of reusing the user's bundler?

We considered reusing the user's bundler (webpack/rollup/vite/rspack/esbuild) to avoid introducing a new dependency. We decided against it because:

  • The user's bundler is configured for their frontend build — different entry points, output settings, plugins, and loaders. Reusing it would mean fighting against that config.
  • Each supported bundler has a different programmatic build API, so we'd need per-bundler codepaths.
  • The plugin system only exposes bundler metadata (name, version, outDir) to plugins, not the bundler instance. Threading the instance through would require factory-level changes.
  • Backend function bundling runs in asyncTrueEnd, after the user's bundler has finished.

esbuild is lightweight, has a simple programmatic API, and is already a transitive dependency for most users (vite ships it). The backend function bundling is a distinct concern from the frontend build — a dedicated tool is simpler and more maintainable.

No externals — The execution environment does not support import or require at runtime, so everything must be inlined into a single bundle per function.

QA Instructions

  1. Configure an app with a backend/ directory containing one or more function modules
  2. Run a production build with APPS_UPLOAD_ASSETS=1 and valid API/app keys
  3. Verify the app upload succeeds and backend functions are included in the upload archive
  4. Confirm the archive contains both frontend/ and backend/ directories with the expected files

Blast Radius

  • No one is using our platform yet — no impact on existing users
  • Only affects apps that have a backend/ directory — no impact on existing apps without backend functions
  • The frontendDir prefixing changes the archive structure for all apps (assets now live under frontend/ instead of the root)
  • The publish step only runs after a successful upload and when valid auth credentials are present

Documentation

@sdkennedy2 sdkennedy2 requested a review from yoannmoinet as a code owner March 10, 2026 17:38
Copy link
Collaborator Author

sdkennedy2 commented Mar 10, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant