As you integrate Cloud Functions into your project, your code could expand to contain many independent functions. You may have too many functions to reasonably fit in a single file, or different teams may deploy different groups of functions, creating a risk of one team overwriting or accidentally deleting another team's functions. Cloud Functions offers different ways to organize your code to make it easier to navigate and maintain your functions.
Organize functions in codebases
You can use the codebase
property of the functions configuration object in firebase.json
to manage a large collection of functions across multiple
repositories or sub-packages within a single repository monorepo setup:
# firebase.json
"functions": {
"codebase": "my-codebase"
# NOTE: Codebase must be less than 63 characters and can contain only
# lowercase letters, numeric characters, underscores, and dashes.
}
The codebase
property is supported in Firebase CLI v10.7.1 and above.
Managing multiple repositories
The codebase
property can help simplify the management of multiple
repositories. Let's examine a case where you have two different repositories
that deploy functions to the same Firebase project:
$
tree
.
├──
repoA
│
├──
firebase.json
│
└──
functions
│
├──
index.js
│
└──
package.json
└──
repoB
├──
firebase.json
└──
functions
├──
index.js
└──
package.json
Without codebase annotations, the Firebase CLI would have prompted you to delete functions defined in the other repository at the time of deploy:
$
(
cd
repoA
&&
firebase
deploy
--
only
functions
)
...
i
functions
:
preparing
functions
directory
for
uploading
...
✔
functions
:
functions
folder
uploaded
successfully
The
following
functions
are
found
in
your
project
but
do
not
exist
in
your
local
source
code
:
fn1FromRepoB
fn2FromRepoB
...
?
Would
you
like
to
proceed
with
deletion
?
Selecting
no
will
continue
the
rest
of
the
deployments
.
(
y
/
N
)
You can avoid this problem by adding a unique codebase annotation in the
functions configuration section of the firebase.json
in each project repository:
# repoA/firebase.json
"functions": {
"codebase": "repo-a"
}
# repoB/firebase.json
"functions": {
"codebase": "repo-b"
}
With codebase annotation, the Firebase CLI no longer prompts you to delete functions defined outside of your immediate repository:
$
(
cd
repoA
&&
firebase
deploy
--
only
functions
)
...
i
functions
:
preparing
functions
directory
for
uploading
...
✔
functions
:
functions
folder
uploaded
successfully
# Gleefully ignores functions from repoB
i
functions
:
creating
Node
.
js
16
function
fnFromRepoA
(
us
-
central1
)
...
✔
Deploy
Complete
!
Managing multiple source packages (monorepo)
The codebase
property can help simplify the management of multiple source
packages in a single repository. Let's examine a case where you have a firebase
project directory with function definitions spread across several sub-packages:
$
tree
.
├──
firebase.json
├──
teamA
│
├──
index.js
│
└──
package.json
└──
teamB
├──
index.js
└──
package.json
This setup fits the following use cases:
- You have a monorepo setup and have different teams manage their own function definitions in an isolated package.
- You have a function with a heavy external dependency and a long-running initialization, and want to isolate that function from other, latency-sensitive functions.
To support monrepo setup like this, define multiple functions configurations
in firebase.json
:
"functions": [
{
"source": "teamA",
"codebase": "team-a"
},
{
"source": "teamB",
"codebase": "team-b"
},
]
With this configuration, the Firebase CLI deploys functions from all packages in a single deploy command:
$
firebase
deploy
--only
functions
i
deploying
functions
i
functions:
preparing
codebase
team-a
for
deployment
i
functions:
preparing
codebase
team-b
for
deployment
i
functions:
creating
Node.js
16
function
team-a:helloATeam (
us-central1 )
...
i
functions:
creating
Node.js
16
function
team-b:helloBTeam (
us-central1 )
...
...
You can also deploy a specific codebase:
$
firebase
deploy
--only
functions:team-b
i
deploying
functions
i
functions:
preparing
codebase
team-b
for
deployment
i
functions:
updating
Node.js
16
function
team-b:helloBTeam (
us-central1 )
...
...
Write functions in multiple files
When getting started with Cloud Functions you might put your first few functions in a single file:
index.js
const
functions
=
require
(
'firebase-functions/v1'
);
exports
.
foo
=
functions
.
https
.
onRequest
((
request
,
response
)
=
>
{
// ...
});
exports
.
bar
=
functions
.
https
.
onRequest
((
request
,
response
)
=
>
{
// ...
});
main.py
from
firebase_functions
import
https_fn
@https_fn
.
on_request
()
def
foo
(
req
:
https_fn
.
Request
)
-
> https_fn
.
Response
:
return
https_fn
.
Response
(
"Hello foo!"
)
@https_fn
.
on_request
()
def
bar
(
req
:
https_fn
.
Request
)
-
> https_fn
.
Response
:
return
https_fn
.
Response
(
"Hello bar!"
)
This can become hard to manage with more than a few functions. Instead, you can put all of your logic for each function in its own file and use your source file as a list of exports:
Node.js
foo.js
const functions = require ( 'firebase-functions/v1' ); exports . foo = functions . https . onRequest (( request , response ) = > { // ... });
bar.js
const functions = require ( 'firebase-functions/v1' ); exports . bar = functions . https . onRequest (( request , response ) = > { // ... });
index.js
const foo = require ( './foo' ); const bar = require ( './bar' ); exports . foo = foo . foo ; exports . bar = bar . bar ;
Python
foo.py
from
firebase_functions
import
https_fn
@https_fn
.
on_request
()
def
foo
(
req
:
https_fn
.
Request
)
-
> https_fn
.
Response
:
return
https_fn
.
Response
(
"Hello foo!"
)
bar.py
from
firebase_functions
import
https_fn
@https_fn
.
on_request
()
def
bar
(
req
:
https_fn
.
Request
)
-
> https_fn
.
Response
:
return
https_fn
.
Response
(
"Hello foo!"
)
main.py
from
fn_impl.foo
import
*
from
fn_impl.bar
import
*
This setup assumes a project directory structure like the following:
my-project
├── firebase.json
└── functions
├── fn_impl
│ ├── __init__.py
│ ├── foo.py
│ └── bar.py
├── main.py
└── requirements.txt
fn_impl
: Can have any name
__init__.py
: Required, but can be empty
Group functions
In many projects, functions can be separated into logical groups that should be deployed and maintained together. For example, you might have a group of functions used for reporting metrics:
metrics.js
const functions = require ( 'firebase-functions/v1' ); exports . usageStats = functions . https . onRequest (( request , response ) = > { // ... }); exports . nightlyReport = functions . https . onRequest (( request , response ) = > { // ... });
You can put these functions into a group when exporting them in your index.js
file:
index.js
// Export both functions from metrics . js in the "metrics" group : // - metrics - usageStats // - metrics - nightlyReport exports . metrics = require ( './metrics' );
When deployed, functions will be prefixed with the name of their group, so
in this example the functions would be named metrics-usageStats
and metrics-nightlyReport
.
When deploying functions you can limit the action to a single group:
firebase deploy -- only functions : metrics
Next steps
To learn more about Cloud Functions , see: