Skip to main content
rule

deno — Cursor rule: what it does and how to install

This rule guides agents working on Deno projects, covering project configuration, imports, permissions, types, and tests. Use it when generating or reviewing JavaScript and TypeScript code.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/deno.mdc
Open on GitHub

What deno does

The rule steers project setup toward deno.json, explicit file extensions in imports, and mod.ts as the main module. It recommends strict TypeScript checks and Deno’s standard library for common tasks.

For code that accesses the network or files, the rule calls for granting only the required --allow-* permissions; without them, those operations can fail. It also points to the built-in deno test runner and _test.ts or _test.js test files. Its advice to avoid tsconfig.json is aimed at Deno-first projects, so it may clash with a project that relies on that file as its main configuration.

What it helps with

  • centralize TypeScript settings and tasks in deno.json
  • fix imports that omit file extensions
  • limit permissions granted to a Deno program
  • add type checks to JavaScript with JSDoc
  • organize tests for deno test

Example prompts for the agent

  • Review this Deno project and move its TypeScript settings and tasks into deno.json.
  • Fix the imports in main.ts by adding file extensions and setting up an import map.
  • Add tests for math.ts using Deno’s built-in test runner.

How to install deno

Manually: put the files in place

.cursor/rules/deno.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about deno

How do I install deno in Cursor?

Create .cursor/rules/deno.mdc in the project and add the rule contents to that file.

What does the deno rule do?

It guides Deno project configuration, imports, permissions, type checking, asynchronous code, and tests.

Which permissions should a Deno program receive?

Only the ones it needs, using --allow-* flags. The rule shows --allow-net=:8080 and --allow-read=. for network and file access.

Source text

deno.mdc · CC0-1.0
---
description: This guide defines definitive Deno best practices for our team, focusing on secure, maintainable, and idiomatic code using Deno's built-in tooling and modern web standards.
globs: **/*.{js,jsx,ts,tsx}
---
# Deno Best Practices

Deno is our runtime of choice for its security, built-in tooling, and first-class TypeScript support. This guide outlines the definitive best practices for writing Deno applications, ensuring consistency, performance, and maintainability across our projects.

## 1. Project Configuration: `deno.json` is King

Always use `deno.json` (or `deno.jsonc`) as the single source of truth for project configuration. This file unifies TypeScript compiler options, Deno-specific flags, tasks, linting, and formatting. Avoid `tsconfig.json` for Deno-first projects.

### ✅ GOOD: Centralized `deno.json`

```json title="deno.json"
{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["deno.window", "deno.unstable"],
    "strict": true,
    "checkJs": true,
    "jsx": "react-jsx"
  },
  "lint": {
    "rules": {
      "tags": ["recommended"]
    }
  },
  "fmt": {
    "options": {
      "useTabs": false,
      "lineWidth": 100,
      "indentWidth": 2,
      "singleQuote": true
    }
  },
  "imports": {
    "std/": "https://deno.land/[email protected]/",
    "oak": "jsr:@oak/oak@16"
  },
  "tasks": {
    "dev": "deno run --allow-net --watch main.ts",
    "test": "deno test --allow-read",
    "start": "deno run --allow-net main.ts"
  }
}
```

### ❌ BAD: Fragmented Configuration

```json title="tsconfig.json"
{
  "compilerOptions": {
    "target": "es2022",
    "strict": true
  }
}
```

```json title="package.json"
{
  "scripts": {
    "dev": "deno run --allow-net --watch main.ts"
  }
}
```

## 2. Module Organization: ES Modules & Explicit Imports

Deno embraces ES modules and URL-based dependencies. Always use explicit file extensions and prefer JSR or `deno.land/x` for external modules.

### 2.1. Explicit URL Imports

Import directly from URLs or use `deno.json`'s `imports` map for cleaner paths.

### ✅ GOOD: URL Imports with Import Map

```typescript title="main.ts"
import { serve } from "std/http/server.ts"; // Uses import map
import { Application } from "oak"; // Uses import map

const app = new Application();
app.listen({ port: 8000 });
console.log("Server running on http://localhost:8000");
```

### ❌ BAD: Missing Extensions or Node.js-style Imports

```typescript title="main.ts"
import { serve } from "https://deno.land/std/http/server"; // Missing .ts extension
import { Application } from "@oak/oak"; // Bare specifier without import map or npm:
```

### 2.2. Entry Point: `mod.ts`

For libraries or main application entry points, name the primary module `mod.ts`.

### ✅ GOOD: `mod.ts` as Entry

```typescript title="mod.ts"
export * from "./src/utils.ts";
export * from "./src/server.ts";
```

### ❌ BAD: `index.ts` for Deno-first projects

```typescript title="index.ts"
export * from "./src/utils.ts";
```

## 3. Security: Explicit Permissions

Deno is secure by default. Always declare necessary permissions explicitly using `--allow-*` flags. Grant the *minimal* required permissions.

### ✅ GOOD: Minimal Permissions

```bash
deno run --allow-net=:8080 --allow-read=. main.ts
```

### ❌ BAD: Overly Permissive or Missing Permissions

```bash
deno run --allow-all main.ts # Too broad
deno run main.ts # Will fail if network/file access is needed
```

## 4. Standard Library Preference

Leverage Deno's built-in standard library (`deno_std`) for common tasks like HTTP, file system, and testing. This reduces external dependencies and maintains consistency.

### ✅ GOOD: Using `deno_std`

```typescript title="file_reader.ts"
import { readAll } from "std/io/read_all.ts";

async function readFileContents(filePath: string): Promise<string> {
  const file = await Deno.open(filePath);
  const contents = await readAll(file);
  Deno.close(file.rid);
  return new TextDecoder().decode(contents);
}
```

### ❌ BAD: Relying on Third-Party for Basic Functionality

```typescript title="file_reader.ts"
// Assuming a third-party 'fs-extra' equivalent exists
import { readFile } from "https://deno.land/x/fs_extra/mod.ts";

async function readFileContents(filePath: string): Promise<string> {
  return await readFile(filePath, { encoding: "utf8" });
}
```

## 5. Type Safety: TypeScript First

Write code in TypeScript (`.ts` or `.tsx`). For JavaScript files, enable type checking with `@ts-check` and use JSDoc for type annotations. Ensure `strict: true` is set in `deno.json`.

### ✅ GOOD: TypeScript with Strict Checks

```typescript title="user.ts"
interface User {
  id: string;
  name: string;
  email?: string; // Optional property
}

function getUserName(user: User): string {
  return user.name;
}
```

### ✅ GOOD: JSDoc for JavaScript

```javascript title="utils.js"
// @ts-check

/**
 * @typedef {object} Product
 * @property {string} id
 * @property {string} name
 * @property {number} price
 */

/**
 * Calculates the total price of products.
 * @param {Product[]} products - List of products.
 * @returns {number} The total price.
 */
function calculateTotalPrice(products) {
  return products.reduce((total, p) => total + p.price, 0);
}
```

### ❌ BAD: Untyped JavaScript or Relaxed TypeScript

```javascript title="user.js"
// No @ts-check, no JSDoc
function getUserName(user) {
  return user.name;
}
```

## 6. Asynchronous Operations: Top-Level `await`

Embrace top-level `await` for cleaner asynchronous code, especially in entry files. Always `await` promises explicitly.

### ✅ GOOD: Top-Level `await`

```typescript title="main.ts"
import { serve } from "std/http/server.ts";

const handler = (req: Request): Response => {
  return new Response("Hello from Deno!");
};

console.log("Server starting...");
await serve(handler, { port: 8000 });
console.log("Server stopped.");
```

### ❌ BAD: IIFEs or Unhandled Promises

```typescript title="main.ts"
import { serve } from "std/http/server.ts";

const handler = (req: Request): Response => {
  return new Response("Hello from Deno!");
};

(async () => { // Unnecessary IIFE
  console.log("Server starting...");
  serve(handler, { port: 8000 }); // Unawaited promise
  console.log("Server stopped."); // Will log immediately
})();
```

## 7. Testing: Built-in `deno test`

Use Deno's built-in test runner (`deno test`) and `deno_std/assert` for writing unit and integration tests. Organize tests in `_test.ts` or `_test.js` files.

### ✅ GOOD: Idiomatic Deno Testing

```typescript title="math_test.ts"
import { assertEquals } from "std/assert/assert_equals.ts";
import { add } from "./math.ts";

Deno.test("add function sums two numbers correctly", () => {
  assertEquals(add(1, 2), 3);
  assertEquals(add(-1, 1), 0);
  assertEquals(add(0, 0), 0);
});
```

```typescript title="math.ts"
export function add(a: number, b: number): number {
  return a + b;
}
```

### ❌ BAD: Third-Party Test Runners or Inconsistent Naming

```typescript title="test.ts"
// Using a third-party test runner not integrated with Deno's ecosystem
import { describe, it, expect } from "https://deno.land/x/some_test_lib/mod.ts";
import { add } from "./math.ts";

describe("add", () => {
  it("should sum numbers", () => {
    expect(add(1, 2)).toBe(3);
  });
});
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

All IDE rules for Programming languages →

From the same set240

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor