Tunneling runs your app code locally on your machine via the Forge CLI and Cloudflare.
Watch our video for an introduction on Forge tunneling.
If you are using a firewall, you might see new connections to Cloudflare tunnel infrastructure. Please allow these for tunneling to work.
More information about this change can be found here.
You can start a tunnel for any app that has been deployed and installed on to a site. To start a tunnel for your app, run the following command in your CLI:
1 2forge tunnel
You'll see output similar to this:
1 2Tunnel redirects requests you make to your local machine. This occurs for any Atlassian site where your app is installed in the specific development environment. You will not see requests from other users. Press Ctrl+C to cancel. === Running forge lint... No issues found. === Bundling code... ✔ Functions bundled. Listening for requests...
Messages logged to the console will look similar to this:
1 2INFO 17:34:04.955 Count of objects in test array: 0
Tunneling also helps you debug your app in two ways:
console.log() statements in your code,
you can see the output in the Forge CLI as the code executes.Variations in your local environment can cause functions to succeed there but fail in Forge. To prevent this:
We are evaluating support for an optional Docker image for tunnelling, based on feedback and interest from Forge app developers.
When running forge tunnel with a UI Kit app, any changes to your source
code triggers a rebundle from the Forge CLI. Once the rebundling is completed successfully, you can
see your changes by refreshing the page that your app is on.
When running forge tunnel with a Custom UI app, the Forge CLI serves
the content from the path directories specified in each resource that's defined in your manifest.
This means that if your static assets require rebundling, you need to bundle them before refreshing
the page that your app is on. See here for more details on resource
declarations for Custom UI apps.
While forge tunnel lets you avoid redeploying your Custom UI app to test changes, you have to
manually bundle it for each change you make. To solve having to do this, popular tools, such as
create-react-app can automatically reload your app each time
you change the code. These tools usually host their own server on a specific port.
For example, running npm start with create-react-app starts a server at http://localhost:3000
by default. The Forge CLI allows you to proxy tunnel requests to these servers, enabling features,
such as hot-reloading while developing your Custom UI apps.
To connect a server to forge tunnel, first identify the port that the server is hosted on.
In the above example, the port would be 3000. Then, add the following to your manifest.yml file,
under the resource your server is hosting:
1 2tunnel: port: <YOUR_PORT_HERE>
For example, a resources definition might look like this:
1 2resources: - key: main path: static/hello-world/build tunnel: port: 3000
Once a port has been added to a resource definition, running forge tunnel causes the Forge CLI
to bypass the path directory, and instead proxy the request to http://localhost:<port>.
You can then run forge tunnel, and start your server by running npm start. You can then see
the assets served by your local server by refreshing the page that your app is on. If your server
supports hot-reloading, you no longer need to refresh the page to see updates when you make
changes to the code.
When running forge tunnel with non-UI functions, such as
Custom UI resolvers and
web triggers, any changes to your source
code triggers a rebundle from the Forge CLI. Once that rebundling is completed successfully,
you can see your changes reflected in the next invocation of the function.
Forge Containers are now available through Forge's Early Access Program (EAP). To start testing this feature, submit your app's ID to our team through this link.
EAPs are offered to selected users for testing and feedback purposes. APIs and features under EAP are unsupported and subject to change without notice. APIs and features under EAP are not recommended for use in production environments.
For more details, see Forge EAP, Preview, and GA.
After defining a containerised service, you can test it locally before you push its image to your container’s repository. You can then use forge tunnel to redirect app invocations from your development site to your local instance of the service.
See Testing a containerised service locally for detailed information on how to set this up.
forge logs. This is because your
app code runs locally while tunneling. forge logs only shows information for your deployed app,
not locally running code.manifest.yml file, you must deploy the app with the latest manifest.
This is needed for the tunnel to pick up the changes.forge tunnel.This section covers common issues that can prevent forge tunnel from working correctly.
If you edit manifest.yml, run forge deploy so the tunnel uses the latest manifest. The tunnel does not replace a deploy. If your change affects installation metadata (for example, permissions or modules), you may also need forge install --upgrade on the target site. Otherwise the tunnel can still run while the app misbehaves or fails.
Use this section if forge tunnel exits immediately, never reaches Listening for requests..., or you suspect traffic is not reaching your machine. A firewall, VPN, or corporate proxy can block Cloudflare tunnel traffic even after the CLI has printed Listening for requests... — still follow Check your network and firewall settings below.
Check your network and firewall settings
forge tunnel uses Cloudflare to route requests from your Atlassian site to your local machine. If a firewall, VPN, or corporate proxy is blocking outbound connections to Cloudflare, the tunnel cannot establish a connection.
To resolve this:
Check that the app is deployed
You must deploy your app at least once before running forge tunnel. The tunnel redirects invocations to your local machine but depends on a deployed version to handle the handshake.
Run the following command to ensure your app is deployed:
1 2forge deploy
Then retry forge tunnel.
Restart the tunnel process
If the tunnel becomes unresponsive or hangs, press Ctrl+C to stop it and run forge tunnel again. Stale tunnel processes can prevent new connections from being established.
If the tunnel is running but you don't see any output when you trigger your app:
development) where your app is installed.forge tunnel. The tunnel only displays your own requests — not those from other users.1 2forge install list
Check Chrome's Local Network Access setting. Chrome has a flag that controls whether sites can make requests to resources on your local network. If this flag is set to Enabled (Blocking), the tunnel silently fails — the CLI shows Listening for requests... but no requests are received.
To fix this, go to chrome://flags/#local-network-access-check in Chrome and set the flag to Default or Disabled.
If you see an authentication error when running forge tunnel, your CLI session may have expired. Re-authenticate by running:
1 2forge login
If the tunnel starts successfully but your app behaves unexpectedly or shows errors:
manifest.yml under app.runtime.name (for example, nodejs20.x, nodejs22.x, or nodejs24.x). If your local Node.js major version does not match that runtime, behaviour may differ from Forge. See Native Node.js runtime, install the matching Node.js release, and use a version manager such as nvm:1 2nvm use 22
Replace 22 with 20 or 24 if your manifest uses nodejs20.x or nodejs24.x.
Check for local-only dependencies. If your code relies on packages or environment-specific globals that aren't bundled with your app, functions may work locally but fail once deployed. Ensure all dependencies are declared in package.json.
Check environment variables. Environment variables must be set locally when tunneling. Variables set in other Forge environments (for example, production) are not accessible to the tunnel. When tunneling, environment variables must be prefixed with FORGE_USER_VAR_ — for example, export FORGE_USER_VAR_MY_KEY=test. In your code, you still access the value as process.env.MY_KEY. See Environments and versions for details.
Review your console output. Any errors thrown by your function will appear in the forge tunnel output. Look for stack traces or unhandled promise rejections that may indicate the root cause.
If forge tunnel hangs at the bundling step and never proceeds:
forge lint to identify issues:1 2forge lint
If you are on macOS with Apple Silicon (M1/M2/M3) and using an older Docker-based version of the Forge CLI, see the Docker bundling issue workaround below.
Delete the node_modules directory and reinstall dependencies, then retry:
1 2rm -rf node_modules && npm install forge tunnel
Older versions of the Forge tunnel use Docker, which may cause issues.
Docker doesn't follow symlinks when creating a container to avoid potential inconsistencies. Therefore, you can't use symlinks in your app repository.
To work around this, install Yalc locally and add dependencies
via yalc add <dependency> before running forge tunnel or forge deploy.
The forge tunnel command will get stuck in the Bundling Code step if you:
To work around this, disable the "Rosetta" setting on your Docker Desktop and restart your Docker daemon.
forge tunnel CLI command.This content is written with standard cloud development in mind. To learn about developing for Atlassian Government Cloud, go to our Atlassian Government Cloud developer portal.
Rate this page: