Import error for a valid relative file path with Supabase Deno Edge Functions
The Context
In my current project, we are using a limited number of Supabase Edge Functions (Serverless) which use the Deno runtime to run any server-side code we need.
The Problem
On my second function (a batch create endpoint), I needed a relative import to get some autogenerated database types:
import { Database as DatabaseType } from '../types/database.types.ts'
According to the relevant Deno docs, this is the correct way to do a relative import, however adding this line introduced the following error when trying to serve the function locally (running the CLI command
supabase functions server <function-name>
):error: Module not found "file:///home/deno/types/database.types.ts". at file:///home/deno/functions/batch-create/index.ts:4:42 2023/01/10 16:32:10 Sent Header: Host [docker] 2023/01/10 16:32:10 Sent Header: User-Agent [Go-http-client/1.1] 2023/01/10 16:32:10 Send Done 2023/01/10 16:32:10 Recv First Byte Error: error executing command
The Solution
The interesting line is
Module not found "file:///home/deno/types/database.types.ts". at file:///home/deno/functions/batch-create/index.ts:4:42
, which tells me the error is with the added import.The interesting thing is the location
home/deno/functions
- the home
directory on my computer is empty, so where is the code actually running?As I used the
supabase
CLI to run the command, I know this could be something I’m doing wrong with Deno, or some unexpected behaviour introduced by the Supabase CLI.I know that, under the hood, Supabase needs the Docker Daemon to run (i.e. I know it uses a Docker process). I run
docker ps
to see all of the processes and find something that looks relevant:CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3caefdac19e0 public.ecr.aws/t3w2s2c9/deno-relay:v1.2.4 "/bin/deno run --all…" 3 minutes ago Up 3 minutes 8081/tcp supabase_deno_relay_backend
I see there’s a linux Docker image running called
supabase_deno_relay_backend
- sounds like this might be where Deno is running my code. Let’s look inside the docker container to check:docker exec -it 3caefdac19e0 bash deno@3caefdac19e0:/app$ ls home deno@3caefdac19e0:/app$ cd /home deno@3caefdac19e0:/home$ ls deno deno@3caefdac19e0:/home$ cd deno deno@3caefdac19e0:~$ ls functions deno@3caefdac19e0:~$ cd functions deno@3caefdac19e0:~/functions$ ls batch-create deno@3caefdac19e0:~/functions$ cd batch-create/ deno@3caefdac19e0:~/functions/batch-create-products$ ls index.ts
cat index.ts
prints out my source code.Going back to the original error, it now makes sense:
Module not found "file:///home/deno/types/database.types.ts"
!The Supabase CLI only copied over source code from within
supabase/functions/
, so importing something locally from outside the functions
directory (e.g. ../../../example.ts
) will trigger Module not found
!Quick solution: move
database.types.ts
within /supabase/functions/
folder so it is copied into the docker image where the runtime environment exists. The Code
Jumping into the
supabase/cli
repo (it’s open source), we can see what’s going on in the file. It’s good to press .
with the repo open on Github to open it in VSCode in the browser. You can then easily cmd+shft+f
(grep search) for home/deno/functions
.You find this file written in Go, which is the directory we are copying files over to.
We can also find the functions dir by grep searching to see where this mapping comes from.
We see that a variable called
binds
is created: binds := []string{filepath.Join(cwd, utils.FunctionsDir) + ":" + relayFuncDir + ":ro,z"}
which maps the two directories (/home/deno/functions
to /supabase/functions
) to one another.The program then runs docker start on the container:
utils.DockerStart( // utils comes from '/supabase/cli/internal/utils' ctx, container.Config{ // container comes from 'docker/api/types/container' Image: utils.DenoRelayImage, Env: append(env, userEnv...), }, container.HostConfig{ Binds: binds, // the binding that maps the '/supabase/functions' dir }, utils.DenoRelayId, )