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.
.cursor/rules/deno.mdcWhat 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.tsby adding file extensions and setting up an import map. - Add tests for
math.tsusing Deno’s built-in test runner.
How to install deno
Manually: put the files in place
.cursor/rules/deno.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/deno.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/deno.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/deno.mdManually: put the files in place
.clinerules/deno.mdStep 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