3 minute read

danet-logo.svg

Welcome ! Your API runs on your machine. Today we put the one we built on the internet.

Deno Deploy runs your JavaScript close to your users and asks for one entrypoint file. That single requirement is the only thing that makes shipping a Danet app different from shipping a script, and the CLI already deals with it.

One command

Install the CLI if you do not have it yet, take an access token from your Deploy account page, and go :

deno install -A -g -n danet jsr:@danet/cli
danet deploy --project my-api --token $DENO_DEPLOY_TOKEN

Few key points :

  • Both options are mandatory. The whole usage line is danet deploy --project <project> --token <token>. deployctl would happily read DENO_DEPLOY_TOKEN from your environment by itself, we do not, so hand it over explicitly.

  • You do not have to create anything in the dashboard first. If the project name does not exist yet, it is created for you.

  • --entrypoint defaults to run.ts, and the bundle is written to ./bundle/bundle.js. That folder is deleted and recreated on every run, so keep nothing precious in it.

  • Three things happen : your app is bundled, deployctl is installed globally, then the bundle is sent up.

  • The first deployment of a project goes to production. Every one after that is a preview deployment with its own URL. That is the opposite of what most people assume, and it is the reason your second deploy seems to change nothing.

To promote a later build, bundle it yourself and call deployctl with --prod :

danet bundle app.js
deployctl deploy --prod --project my-api bundle/app.js

Why a bundle

danet bundle shells out to deno bundle, which came back in Deno 2.4 and now folds your whole module graph, JSR dependencies included, into one file.

The part that matters for us : decorator metadata survives the trip. Controllers keep their routes and constructor injection keeps resolving, so the bundle behaves exactly like deno run run.ts did.

deno bundle prints a warning that it is experimental and subject to change. Take it seriously, it is their word not ours.

Not by hand every time

But Thomas, I am not pasting an API token into a terminal every time I ship !

Of course not. Projects generated by danet new already carry .github/workflows/run-tests.yml, which lints, tests, bundles and deploys. Put your project name in the last step and that is the setup done.

```yaml .github/workflows/run-tests.yml name: Run tests and Deploy to Deno Deploy

on: push: branches: [main]

permissions: contents: read id-token: write # needed to authenticate with Deno Deploy

jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4

  - uses: denoland/setup-deno@v2
    with:
      deno-version: v2.x

  - name: Run tests
    run: deno task test

  - name: Install Danet CLI
    run: deno install -A -g -n danet jsr:@danet/cli

  - name: Bundle app with Danet CLI
    run: danet bundle run.js

  - name: Deploy to Deno Deploy
    uses: denoland/deployctl@v1
    with:
      project: my-api
      entrypoint: run.js
      root: bundle ```

Few key points :

  • No secret to configure. id-token: write is what lets the action prove who it is, provided the Deploy project is linked to the repository.

  • In your project settings, the deployment mode has to be GitHub Actions, not Automatic. Automatic ships your repository as it is, and we need the bundle step to run first.

  • The argument to danet bundle is the output name, the input is --entrypoint. So danet bundle run.js reads run.ts and writes bundle/run.js, which is why the last step says entrypoint: run.js and root: bundle.

  • The generated run.ts listens on Number(Deno.env.get('PORT') || 3000). Keep it that way, the platform picks the port.

What it costs

There is a free tier, generous enough for a side project, and a paid one when you outgrow it. The numbers move often enough that printing them here would be a disservice : read them at https://deno.com/deploy/pricing.

Well, that’s it folks ! It wasn’t hard, now you know !

To learn more about Danet, check out our documentation : https://danet.land

And the GitHub repository if you want to contribute : https://github.com/Savory/Danet

Updated: