---
title: Quick Start
description: Fastest path to a running scheduled DurableStack job in .NET or Node.js.
order: 12
available_in: [dotnet, nodejs]
---

This is the fastest path to a running recurring job using PostgreSQL.

Use the runtime you already ship with and keep the same execution model.

## 1) Install package

:::code-group
```csharp
// Terminal
dotnet add package DurableStack.Hosting
```

```typescript
// Terminal
npm install durablestack
```
:::

## 2) Create a recurring job

:::code-group
```csharp
using DurableStack.Core.Abstractions;
using DurableStack.Core.Models;
using DurableStack.Hosting.DependencyInjection;

[DurableJob(Name = "heartbeat-every-minute", MaxAttempts = 3)]
[RecurringJob("* * * * *", TimeZone = "UTC")]
public sealed class HeartbeatJob : IDurableJob
{
    public Task ExecuteAsync(JobContext context, CancellationToken cancellationToken = default)
    {
        Console.WriteLine($"Heartbeat from run {context.RunId}");
        return Task.CompletedTask;
    }
}
```

```typescript
runtime.registerRecurring("heartbeat-every-minute", "* * * * *", "UTC", async () => {
  console.log("Heartbeat from Node.js runtime");
});
```
:::

## 3) Configure DurableStack

:::code-group
```csharp
using DurableStack.Core.Abstractions;
using DurableStack.Core.Options;
using DurableStack.Hosting.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
var connectionString = "REAL_CONNECTION_STRING";

builder.Services.AddDurableStackPostgres(connectionString, options =>
{
    // Optional hosted observability
    options.Eventing.TenantId = null;
    options.Eventing.ClientSecret = null;
});

var app = builder.Build();

app.Run();
```

```typescript
import { createDurableStackPostgres } from "durablestack";

const { runtime, closeStore } = await createDurableStackPostgres(
  { connectionString: process.env.DATABASE_URL! },
  {
    workerName: "orders-api-node-1",
    eventing: {
      tenantId: "",
      clientSecret: ""
    }
  }
);

runtime.registerRecurring("heartbeat-every-minute", "* * * * *", "UTC", async () => {
  console.log("Heartbeat from Node.js runtime");
});

await runtime.start();

process.on("SIGTERM", async () => {
  await runtime.stop();
  await closeStore();
});
```
:::

## 4) Run and verify

- Start the runtime.
- Wait one minute.
- Confirm the recurring heartbeat runs in application logs.

## 5) Optional: enable hosted observability

Set tenant credentials in your runtime configuration:

:::code-group
```csharp
using DurableStack.Hosting.DependencyInjection;

options.Eventing.TenantId = "your-tenant-id";
options.Eventing.ClientSecret = "your-client-secret";
```

```typescript
import { createDurableStackPostgres } from "durablestack";

const { runtime } = await createDurableStackPostgres(
  { connectionString: process.env.DATABASE_URL! },
  {
    eventing: {
      tenantId: "your-tenant-id",
      clientSecret: "your-client-secret"
    }
  }
);
```
:::

When both are set, event ingestion is enabled automatically.

## Continue

- [Getting Started](getting-started)
- [First Job Example](first-job-example)
- [Recurring Jobs](../usage-guide/recurring-jobs)
