Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions box/guides/nextjs-setup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: "Next.js Setup"
---

This guide walks you through scaffolding a [Next.js](https://nextjs.org) app inside an Upstash Box and opening it in your browser through a public URL, without using an agent.

The box gives you a full Linux environment with Node.js already installed, so you can create the app, run the dev server, and share it, all through the SDK.

---

## 1. Create a Box

Create a box with the `node` runtime. You don't need to configure an agent for this. See the [quickstart](/box/overall/quickstart) if you haven't created one before.

<CodeGroup>
```typescript box.ts
import { Box } from "@upstash/box"

const box = await Box.create({ runtime: "node" })
```

```python box.py
from upstash_box import Box

box = Box.create(runtime="node")
```
</CodeGroup>

---

## 2. Scaffold the App

Run `create-next-app` inside the box. The `--yes` flag accepts the default options so the setup runs without prompts, installing all dependencies.

<CodeGroup>
```typescript box.ts
await box.exec.command("npx --yes create-next-app@latest my-next-app --yes")
```

```python box.py
box.exec.command("npx --yes create-next-app@latest my-next-app --yes")
```
</CodeGroup>

---

## 3. Start the Dev Server

Start the development server in the background so the command returns while Next.js keeps running on port `3000`. Commands run from the box's home directory (`/workspace/home`), where the app was created.

<CodeGroup>
```typescript box.ts
await box.exec.command("cd my-next-app && nohup npm run dev > dev.log 2>&1 &")
```

```python box.py
box.exec.command("cd my-next-app && nohup npm run dev > dev.log 2>&1 &")
```
</CodeGroup>

---

## 4. Create a Public URL

Expose port `3000` with a public URL to view the app in your browser. Creating a public URL for a running server returns its address.

<CodeGroup>
```typescript box.ts
const publicUrl = await box.getPublicURL(3000)

console.log(publicUrl.url)
// → https://<box-id>-3000.preview.box.upstash.com
```

```python box.py
public_url = box.get_public_url(3000)

print(public_url.url)
# -> https://<box-id>-3000.preview.box.upstash.com
```
</CodeGroup>

Open the URL in your browser and your Next.js app loads. See [Public URLs](/box/overall/preview) for authentication and other options.

<Note>
Next.js blocks cross-origin dev resources by default, so hot reloading won't work over the public URL until you add the host to `allowedDevOrigins` in `next.config.ts`:

```typescript next.config.ts
const nextConfig: NextConfig = {
allowedDevOrigins: ["<box-id>-3000.preview.box.upstash.com"],
}
```
</Note>
2 changes: 1 addition & 1 deletion box/overall/ephemeral-box.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The request sends `{ ephemeral: true, ttl?, runtime? }` to `POST /v2/box`.
| `expiresAt` | No | Yes |
| `agent.run()` / `agent.stream()` | Yes | **No** |
| `git.*` | Yes | **No** |
| `getPublicUrl()` / `listPublicUrls()` / `deletePublicUrl()` | Yes | **No** |
| `getPublicURL()` / `listPublicURLs()` / `deletePublicURL()` | Yes | **No** |
| `snapshot()` / `fromSnapshot()` | Yes | Yes |
| `pause()` / `resume()` | Yes | **No** |
| `configureModel()` | Yes | **No** |
Expand Down
40 changes: 20 additions & 20 deletions box/overall/preview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ await box.files.write({
await box.exec.command("node /work/server.js &")

// Create a public URL
const publicUrl = await box.getPublicUrl(3000)
const publicUrl = await box.getPublicURL(3000)

console.log(publicUrl.url)
// → https://{BOX_ID}-3000.preview.box.upstash.com
Expand Down Expand Up @@ -71,13 +71,13 @@ Protect your public URL with bearer token or basic authentication.
<CodeGroup>
```typescript box.ts
// With bearer token
const publicUrl = await box.getPublicUrl(3000, { bearerToken: true })
const publicUrl = await box.getPublicURL(3000, { bearerToken: true })

console.log(publicUrl.token) // Use this in Authorization header
// → "63d8b153..."

// With basic auth
const publicUrl = await box.getPublicUrl(8080, { basicAuth: true })
const publicUrl = await box.getPublicURL(8080, { basicAuth: true })

console.log(publicUrl.username) // → "user"
console.log(publicUrl.password) // → "f0f145f0..."
Expand Down Expand Up @@ -108,7 +108,7 @@ Creates a public URL that exposes a port on your box. Returns the URL and authen

<CodeGroup>
```typescript box.ts
const publicUrl = await box.getPublicUrl(3000)
const publicUrl = await box.getPublicURL(3000)

console.log(publicUrl.url)
// → https://{BOX_ID}-3000.preview.box.upstash.com
Expand All @@ -128,7 +128,7 @@ Add `bearerToken: true` to require an authorization header when accessing the pu

<CodeGroup>
```typescript box.ts
const publicUrl = await box.getPublicUrl(3000, { bearerToken: true })
const publicUrl = await box.getPublicURL(3000, { bearerToken: true })

console.log(publicUrl.token)
// → "63d8b153..."
Expand All @@ -154,7 +154,7 @@ Add `basicAuth: true` to require username and password when accessing the public

<CodeGroup>
```typescript box.ts
const publicUrl = await box.getPublicUrl(8080, { basicAuth: true })
const publicUrl = await box.getPublicURL(8080, { basicAuth: true })

console.log(publicUrl.username) // → "user"
console.log(publicUrl.password) // → "f0f145f0..."
Expand All @@ -180,7 +180,7 @@ Enable both authentication methods. Either one will work when accessing the publ

<CodeGroup>
```typescript box.ts
const publicUrl = await box.getPublicUrl(8080, { bearerToken: true, basicAuth: true })
const publicUrl = await box.getPublicURL(8080, { bearerToken: true, basicAuth: true })

console.log(publicUrl.token) // → "63d8b153..."
console.log(publicUrl.username) // → "user"
Expand All @@ -204,9 +204,9 @@ Get all active public URLs for this box.

<CodeGroup>
```typescript box.ts
const { publicUrls } = await box.listPublicUrls()
const { publicURLs } = await box.listPublicURLs()

console.log(publicUrls)
console.log(publicURLs)
// [
// { url: "https://{BOX_ID}-3000.preview.box.upstash.com", port: 3000 },
// { url: "https://{BOX_ID}-8080.preview.box.upstash.com", port: 8080 },
Expand All @@ -232,7 +232,7 @@ Remove a public URL by port number.

<CodeGroup>
```typescript box.ts
await box.deletePublicUrl(3000)
await box.deletePublicURL(3000)
```

```python box.py
Expand All @@ -251,10 +251,10 @@ Creating a public URL for a port that already has one will overwrite the previou
<CodeGroup>
```typescript box.ts
// First public URL
const publicUrl1 = await box.getPublicUrl(3000)
const publicUrl1 = await box.getPublicURL(3000)

// Second public URL overwrites the first one
const publicUrl2 = await box.getPublicUrl(3000, { bearerToken: true })
const publicUrl2 = await box.getPublicURL(3000, { bearerToken: true })

// publicUrl1.url is no longer accessible
```
Expand Down Expand Up @@ -285,7 +285,7 @@ Creating a public URL on a paused box automatically resumes it.
await box.pause()

// This will resume the box
const publicUrl = await box.getPublicUrl(3000)
const publicUrl = await box.getPublicURL(3000)
```

```python box.py
Expand Down Expand Up @@ -327,7 +327,7 @@ Create a simple Express web server that:
`,
})

const publicUrl = await box.getPublicUrl(3000)
const publicUrl = await box.getPublicURL(3000)
console.log(`Public URL available at: ${publicUrl.url}`)

// Test the endpoints
Expand Down Expand Up @@ -397,7 +397,7 @@ if __name__ == '__main__':
await box.exec.command("pip install flask && python /work/app.py &")

// Create authenticated public URL
const publicUrl = await box.getPublicUrl(8080, { basicAuth: true })
const publicUrl = await box.getPublicURL(8080, { basicAuth: true })

console.log(`Public URL: ${publicUrl.url}`)
console.log(`Username: ${publicUrl.username}`)
Expand Down Expand Up @@ -477,8 +477,8 @@ await box.exec.command("npm install express")
await box.exec.command("node /work/frontend.js & node /work/api.js &")

// Create a public URL for each service
const frontendPublicUrl = await box.getPublicUrl(3000)
const apiPublicUrl = await box.getPublicUrl(8080)
const frontendPublicUrl = await box.getPublicURL(3000)
const apiPublicUrl = await box.getPublicURL(8080)

console.log(`Frontend: ${frontendPublicUrl.url}`)
console.log(`API: ${apiPublicUrl.url}`)
Expand Down Expand Up @@ -537,14 +537,14 @@ const box = await Box.create({ runtime: "node" })
await box.exec.command("npx http-server /work -p 3000 &")

// Create a public URL for testing
const publicUrl = await box.getPublicUrl(3000)
const publicUrl = await box.getPublicURL(3000)

// Run your tests against the public URL
const response = await fetch(publicUrl.url)
console.log(response.status) // 200

// Clean up
await box.deletePublicUrl(3000)
await box.deletePublicURL(3000)
await box.delete()
```

Expand All @@ -571,4 +571,4 @@ box.delete()
</CodeGroup>


<Note>The SDK still supports `getPreviewUrl`, `listPreviews`, and `deletePreview`, but they are deprecated aliases for `getPublicUrl`, `listPublicUrls`, and `deletePublicUrl`.</Note>
<Note>The SDK still supports `getPreviewUrl`, `listPreviews`, and `deletePreview`, but they are deprecated aliases for `getPublicURL`, `listPublicURLs`, and `deletePublicURL`.</Note>
2 changes: 1 addition & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1680,7 +1680,7 @@
},
{
"group": "Guides",
"pages": ["box/guides/remote-development", "box/guides/code-review-agent", "box/guides/web-scraping-playwright", "box/guides/ai-sdk-code-interpreter", "box/guides/tanstack-ai-file-editor", "box/guides/openclaw-setup", "box/guides/hermes-setup", "box/guides/crabbox-setup"]
"pages": ["box/guides/remote-development", "box/guides/nextjs-setup", "box/guides/code-review-agent", "box/guides/web-scraping-playwright", "box/guides/ai-sdk-code-interpreter", "box/guides/tanstack-ai-file-editor", "box/guides/openclaw-setup", "box/guides/hermes-setup", "box/guides/crabbox-setup"]
}
]
},
Expand Down
Loading