Managing Deno Imports in Supabase Edge Functions — deno.json, Version Pinning, Zero Lint

typescript dev.to

Managing Deno Imports in Supabase Edge Functions

Deno Uses URL-Based Imports

Unlike Node.js, Deno has no npm install. Imports are ESM URLs:

// Node.js (doesn't work in Deno)
import { createClient } from 'supabase';

// Deno (correct)
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
Enter fullscreen mode Exit fullscreen mode

Pin Your Versions

// ❌ Unpinned — will break on next major release
import { Hono } from 'https://deno.land/x/hono/mod.ts';

// ✅ Pinned
import { Hono } from 'https://deno.land/x/hono@v4.7.0/mod.ts';
Enter fullscreen mode Exit fullscreen mode

The @latest alias on deno.land resolves dynamically. An unpinned import that works today can silently break tomorrow.

Centralize with deno.json

Put a deno.json in supabase/functions/ to alias all imports:

{"imports":{"@supabase/supabase-js":"https://esm.sh/@supabase/supabase-js@2.49.4","hono":"https://deno.land/x/hono@v4.7.0/mod.ts","hono/cors":"https://deno.land/x/hono@v4.7.0/middleware/cors/index.ts"}}
Enter fullscreen mode Exit fullscreen mode

Each Edge Function imports by alias:

import { createClient } from '@supabase/supabase-js';
import { Hono } from 'hono';
Enter fullscreen mode Exit fullscreen mode

Version upgrades: change one line in deno.json, all EFs update.

Shared Utilities with _shared/

Avoid repeating Supabase client initialization in every EF:

// supabase/functions/_shared/supabase.ts
import { createClient } from '@supabase/supabase-js';

export function getClient(req: Request) {
  const auth = req.headers.get('Authorization')!;
  return createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_ANON_KEY')!,
    { global: { headers: { Authorization: auth } } }
  );
}

export function getAdminClient() {
  return createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  );
}
Enter fullscreen mode Exit fullscreen mode

Keep deno lint at Zero

deno lint runs in CI. Common violations to avoid:

// ❌ prefer-const — reassigned never → must be const
let count = 0;

// ✅
const count = 0;

// ❌ no-explicit-any
function process(data: any) {}

// ✅ use unknown and narrow
function process(data: unknown) {
  if (typeof data === 'string') { ... }
}
Enter fullscreen mode Exit fullscreen mode

Run after every EF change:

deno lint supabase/functions/
Enter fullscreen mode Exit fullscreen mode

import_map.json vs deno.json

Older Supabase projects use import_map.json. Migrate to deno.json:

mv supabase/functions/import_map.json supabase/functions/deno.json
# Wrap content: { "imports": { ...same content... } }
Enter fullscreen mode Exit fullscreen mode

Summary

Concern Solution
Version drift Pin with @x.y.z in every URL
Many EFs same imports deno.json imports aliases
Repeated client init _shared/supabase.ts utility
CI lint failures deno lint after every EF edit

Good import hygiene means zero "works locally, breaks in CI" surprises.


Building in public: https://my-web-app-b67f4.web.app/

Supabase #Deno #TypeScript #buildinpublic #EdgeFunctions

Source: dev.to

arrow_back Back to Tutorials