# Building Netlify functions with dependencies

**URL:** <https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751>\
**Category:** Support\
**Tags:** edge\_functions, netlify-newbie, deployment\
**Created:** [July 16, 2023, 1:54pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751 "2023-07-16T13:54:02Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nexxon](https://sea1.discourse-cdn.com/netlify/user_avatar/answers.netlify.com/nexxon/32/52767_2.png) [@Nexxon](https://answers.netlify.com/u/Nexxon)\
**Post date:** [July 16, 2023, 1:54pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751/1 "2023-07-16T13:54:02Z")

</div>

Hello 🙂

I am trying to write and deploy my first Netlify edge function. The goal is to send notifications via Firebase Cloud Messaging. I created a send-notification.js file that requires two npm dependencies.  
When running `netlify dev` everything works fine.  
However, when i deploy my app the build fails due to the external dependencies:

```auto
3:38:33 PM: Edge Functions bundling                                       
3:38:33 PM: ────────────────────────────────────────────────────────────────
3:38:33 PM: ​
3:38:33 PM: Packaging Edge Functions from netlify/edge-functions directory:
3:38:33 PM: - send-notifications
3:38:34 PM: error: Uncaught (in promise) Error: Relative import path firebase-admin/messaging not prefixed with / or ./ or ../ and not in import map from file:///root/netlify/edge-functions/send-notifications.js
3:38:34 PM: const ret = new Error(getStringFromWasm0(arg0, arg1));
3:38:34 PM: ^
3:38:34 PM: at __wbg_new_15d3966e9981a196 (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:417:19)
3:38:34 PM: at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:93412)
3:38:34 PM: at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:1499594)
3:38:34 PM: at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:1938165)
3:38:34 PM: at __wbg_adapter_40 (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:231:6)
3:38:34 PM: at real (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:215:14)
3:38:34 PM: at eventLoopTick (ext:core/01_core.js:182:11)
3:38:34 PM: ​
3:38:34 PM: Bundling of edge function failed                              
3:38:34 PM: ────────────────────────────────────────────────────────────────
3:38:34 PM: ​
3:38:34 PM: Error message
3:38:34 PM: It seems like you're trying to import an npm module. This is only supported via CDNs like esm.sh. Have you tried 'import mod from https://esm.sh/firebase-admin/messaging'?
​
3:38:34 PM: Error location
3:38:34 PM: While bundling edge function
3:38:34 PM: ​
3:38:34 PM: Resolved config
3:38:34 PM: build:
3:38:34 PM: command: npm install
3:38:34 PM: commandOrigin: ui
3:38:34 PM: edge_functions: /opt/build/repo/netlify/edge-functions
3:38:34 PM: publish: /opt/build/repo
3:38:34 PM: publishOrigin: ui
3:38:34 PM: functionsDirectory: /opt/build/repo/netlify/edge-functions
3:38:34 PM: redirects:
3:38:35 PM: Build failed due to a user error: Build script returned non-zero exit code: 2
3:38:35 PM: Failing build: Failed to build site
3:38:35 PM: Finished processing build request in 13.933s

```

I also tried to import the dependencies via CDN but without success. Ideally i would like it to work with the dependencies defined in my package.json.

For anyone wondering this is my project setup:  
netlify.toml

```auto
[build]
    external_node_modules = ["firebase-admin", "dotenv"]
    functions = "netlify/edge-functions/"

[[redirects]]
    from = "/api/*"
    to = "/.netlify/functions/:splat"
    status = 200

```

My netlify edge function:  
netlify/edge-functions/send-notifications.js

```auto
import { initializeApp, applicationDefault } from 'firebase-admin/app';
import dotenv from 'dotenv';
import { getMessaging } from 'firebase-admin/messaging';

dotenv.config();
const credentialsPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
console.log(credentialsPath);

initializeApp({
  credential: applicationDefault(),
  projectId: 'shared-list-preview',
});

export async function handler(event, context) {
  console.log('Send notifications called')

  if (event.httpMethod === undefined && event.httpMethod !== 'POST') {
    return {
      statusCode: 400,
      body: JSON.stringify({
        error: 'Only post requests allowed.'
      }),
    };
  } else {
    const requestBody = JSON.parse(event.body)
    if (isEmpty(requestBody.title) || isEmpty(requestBody.text) || isEmpty(requestBody.fcmTokens)) {
      return {
        statusCode: 400,
        body: JSON.stringify({
          error: 'Body must contain title, text and fcmTokens.'
        }),
      };
    }
  }

  const requestBody = JSON.parse(event.body)
  const message = {
    notification: {
      title: requestBody.title,
      body: requestBody.text,
    },
    tokens: requestBody.fcmTokens
  }

  try {
    const batchResponse = await getMessaging().sendEachForMulticast(message);
    // Return a success response
    if (batchResponse.failureCount === 0) {
      const successMsg = `Successfully sent ${batchResponse.successCount} message(s)`
      console.log(successMsg)
      return {
        statusCode: 200,
        body: JSON.stringify({
          message: successMsg
        }),
      };
    } else {
      const failureMsg = `Failure - Was able to sent ${batchResponse.successCount}/${batchResponse.failureCount} message(s)`
      console.log(failureMsg)
      return {
        statusCode: 500,
        body: JSON.stringify({
          message: failureMsg,
          responses: batchResponse.responses
        }),
      }
    }
  } catch (error) {
    console.log('Error sending message:', error);
    return {
      statusCode: 500,
      body: JSON.stringify({
        error: error.message
      }),
    };
  }
}

function isEmpty(str) {
  return (!str || str.length === 0 );
}

```

(I get warnings locally, if anyone knows how to get rid of them I would be happy to know:)

```auto
◈ Loaded edge function send-notifications
◈ Failed to run Edge Function send-notifications:
TypeError: Relative import path "firebase-admin/messaging" not prefixed with / or ./ or ../ and not in import map from "my-project/netlify/edge-functions/send-notifications.js"
    at my-project/netlify/edge-functions/send-notifications.js:3:30
    at async file:///user/AppData/Local/Temp/tmp-31204-qKAJa6073fym/dev.js:7:35 {
  code: "ERR_MODULE_NOT_FOUND"

```

I would gladly appreciate any hints! Thank you so much 🙂

---

<div class="post-metadata">

**Author:** ![hrishikesh](https://sea1.discourse-cdn.com/netlify/user_avatar/answers.netlify.com/hrishikesh/32/74607_2.png) [@hrishikesh](https://answers.netlify.com/u/hrishikesh)\
**Post date:** [July 16, 2023, 3:27pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751/2 "2023-07-16T15:27:17Z")

</div>

You’re trying to use Netlify Functions, but instead using Edge Functions. Simply move it from `netlify/edge-functions` to `netlify/functions`.

> [@Nexxon](#):
>
> ```auto
> [build]
> external_node_modules = ["firebase-admin", "dotenv"]
> functions = "netlify/edge-functions/"
> 
> ```

and remove this.

---

<div class="post-metadata">

**Author:** ![Nexxon](https://sea1.discourse-cdn.com/netlify/user_avatar/answers.netlify.com/nexxon/32/52767_2.png) [@Nexxon](https://answers.netlify.com/u/Nexxon)\
**Post date:** [July 16, 2023, 4:15pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751/3 "2023-07-16T16:15:47Z")

</div>

Hey hrishikesh

Thank you so much for the fast response. That actually fixed the issue!

I have another follow up question, would be glad if you could point me in the right direction there as well!  
In my code I am reading a json file from an environment variable:

```auto
const credentialsPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;

```

Currently i have the required json file in the root of my project and this variable points to that file. However, i think it is not deployed with my app:  
`"errorMessage":"Failed to read credentials from file ./my-credentials-file.json: Error: ENOENT: no such file or directory`

My question is - how can I access this file in a netlify function? Or even better - Is there a more secure way to handle this with netlify because i don’t really want that file to be checked in my code.

---

<div class="post-metadata">

**Author:** ![hrishikesh](https://sea1.discourse-cdn.com/netlify/user_avatar/answers.netlify.com/hrishikesh/32/74607_2.png) [@hrishikesh](https://answers.netlify.com/u/hrishikesh)\
**Post date:** [July 16, 2023, 4:39pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751/4 "2023-07-16T16:39:54Z")

</div>

Why not add the contents of the JSON file to an environment variable and use that value instead? If you absolutely need a JSON file instead of a JSON string, I’d recommend the following approach:

```auto
import {writeFileSync} from 'fs'
writeFileSync('/tmp/credentials.json', JSON.stringify({
  key1: process.env.VALUE_1 // add each key as a variable (personal recommendation, but you can choose to save it as one string too)
})) // AWS Lambda only provides write access to `/tmp/`

```

and then use `/tmp/credentials.json` as the file path.

---

<div class="post-metadata">

**Author:** ![Nexxon](https://sea1.discourse-cdn.com/netlify/user_avatar/answers.netlify.com/nexxon/32/52767_2.png) [@Nexxon](https://answers.netlify.com/u/Nexxon)\
**Post date:** [July 16, 2023, 5:55pm UTC](https://answers.netlify.com/t/building-netlify-functions-with-dependencies/96751/5 "2023-07-16T17:55:07Z")

</div>

The default way is by pointing to the json file but thanks for the hint. I found a way to use a set of environment variables instead. Thank youuu 🙂
