# Quickstart

> Install the SDK, define a job, run it locally with runnel dev and deploy it to Runnel Cloud. About five minutes, in TypeScript.

Source: https://galley.themes.dev/docs/getting-started/quickstart/

This guide takes you from an empty folder to a job running in Runnel Cloud. It uses TypeScript and Node 20; the same steps work in Python and Go with the commands in [Installation](/docs/getting-started/installation/). You need a free Runnel account, which you can create at app.runnel.example.

## 1. Install the SDK and the CLI

In a new or existing Node project:

```bash
npm install @runnel/sdk
npx runnel login
```

`runnel login` opens your browser, asks you to pick a project and stores a token in `~/.config/runnel/credentials`. The CLI comes with the SDK, so `npx runnel` works without a global install.

## 2. Define a job

Create a job file. A job is a name, some options and a function that receives the payload.

```ts title="src/jobs/send-welcome.ts"
import { runnel } from '@runnel/sdk';

export const sendWelcome = runnel.job({
  name: 'send-welcome',
  retries: { attempts: 3 },
  run: async (payload: { email: string; name: string }, ctx) => {
    ctx.log.info('sending welcome email', { email: payload.email });
    await new Promise((resolve) => setTimeout(resolve, 500)); // stand-in for your mailer
    return { sent: true };
  },
});
```

Then a worker that knows about it, and a config file that points at the worker:

```ts title="src/worker.ts"
import { runnel } from '@runnel/sdk';
import { sendWelcome } from './jobs/send-welcome';

runnel.worker({ jobs: [sendWelcome] }).start();
```

```ts title="runnel.config.ts"
import { defineConfig } from '@runnel/sdk';

export default defineConfig({ project: 'quickstart', worker: './src/worker.ts' });
```

## 3. Run it locally

```bash
npx runnel dev
```

`runnel dev` starts a local Runnel server, starts your worker and reloads it when a file changes. Nothing is sent to Runnel Cloud. The local dashboard is at `http://localhost:8288`.

Enqueue a run from a second terminal, from a script or from your app:

```ts title="scripts/try.ts"
import { sendWelcome } from '../src/jobs/send-welcome';

const run = await sendWelcome.enqueue({ email: 'ada@example.com', name: 'Ada' });
console.log(run.id); // run_01JB7X2K9Q4MZ8
```

In the dashboard you will see the run move from `queued` to `running` to `succeeded`, with its log line and its output, `{ "sent": true }`.

> **Tip** Throw an error inside `run` and enqueue again. You will see three attempts, each with its own log and stack trace, spaced out by the default backoff, before the run ends as `failed`.

## 4. Deploy

Deploying registers your job definitions with Runnel Cloud. Your worker still runs on your own infrastructure.

```bash
npx runnel deploy --env production
# Deployed v1 to production: 1 job, 0 workflows, 0 schedules
```

Create a production API key in the dashboard under **Settings › API keys**, set it as `RUNNEL_API_KEY` wherever the worker runs, and start it with `node dist/worker.js`. The worker connects out to Runnel over HTTPS and starts taking runs. [Deploying workers](/docs/guides/deploying/) covers containers, Kubernetes and serverless platforms.

> **Warning** Keys starting with `rk_live_` can enqueue and cancel runs in production. Keep them out of your repository and out of browser code.

## What you have now

- A job, `send-welcome`, defined in your own code and versioned with it.
- A local setup that runs it without touching the cloud.
- A production deployment, `v1`, with every run recorded in the dashboard.

From here, read [Core concepts](/docs/getting-started/concepts/) to learn how runs, attempts and steps relate, or go straight to [Retries and timeouts](/docs/guides/retries/) and [Workflows](/docs/guides/workflows/).
