Serving local terrain in Cesium

Can Cesium load/render terrain from a local file path or does it have to be served from a web server so that it knows the encoding type?

I'm currently working on an Electron based application that makes use of Cesium. I was hoping to just use a local file reference to the terrain but haven't been able to get it to work. As soon as I start up a server and point it at the terrain, it works perfectly. It seems to be because I can tell it the content type and encoding using the http headers from the server so it knows how to handle the data. Can anyone confirm this? Is there a way that I can use terrain locally without having to have a server in the mix?


You should be able to use local terrain. We have instructions for offline apps here:

And we have a blog post for using electron here:




Thanks for the reply. I'm WAY past getting it to work in Electron. I'm just having issues getting terrain to load locally as opposed to via a server.

I setup a basic nodejs based web server using express and if I serve terrain that way, it works perfectly. Attempting to run it from a file path is causing issues though.

Checking in the Chrome Dev Tools, I can see where it's making the CesiumTerrainProvider, the path is set correctly. I can see in the Network tab where it makes the request and loads the layer.json and the first 0.terrain files. I THINK my issue is coming up because, when I setup the web server, I had to specify content type and content encoding headers in the response so it would know how to handle the data. When running locally, it still makes the request but it doesn't have the headers necessary for it to properly handle the response data (of the terrain files). I think that is the issue.

Do you have any idea how to resolve that?

Also, I'm not sure if this is the intended case but when I was attempting to create a CesiumTerrainProvider because, I was attempting to set the url to file:///Users/etc.. and it would show the correct path in the resultant objects _url property but when it made the actual request, it removed the 3rd / and made the "U" in Users lowercase which.. seems like it would have broken things on a Mac because of the case sensitivity of the system.

Oh okay. I understand what you’re saying now. I’m not 100% positive, but I do think you will need a local server to deliver the tiles. There are usually security measures in place that prevent the browser from accessing things directly in the file system.
Does anyone have more insight on this?


I believe I do too. If that's the case, it should probably be noted on the link provided above that running offline only works for imagery and not for terrain.

There is zero reason that terrain should not work offline via Electron. Are you using gzipped tiles? (sounds like you are since you mentioned content-encoding). You need to either configure Electron so that it knows the encoding on those tiles (which Electron may not even support, I’m not sure), or just ungzip all of your data. I would recommend ungzipping the data as a test either way.

Thanks Matt. I'll try gunzipping it all. With the exception of.. who knows how big these terrain layers are gonna be now haha, I hope its the solution. Since I'm building a desktop app, I'd really like to not have to integrate a server in just to get the terrain to work. I've done it for now until I can get all this stuff converted over and try again.

Thanks again

It seems to want to work except now its throwing an error attempting to request


I'm getting a 404 of those. It looks as if it's trying to use path relative to the html file that is currently loaded instead of from the Cesium path the way it normally does. I'm still getting a transparent globe without those two. I'm not really sure where to go from here.

Sounds like a potential configuration issue in your Electron set up and Cesium can’t find its web workers. Are you using the combined Cesium.js file and are all of the standard Cesium directories (Assets/Workers/Widgets/etc…) located alongside it? If not, what module system are you using?

I’m going to guess creating async geometry or anything else that uses workers will fail for you to.

As a shot in the dark, you can try setting the global variable CESIUM_BASE_URL to the location of the Cesium.js folder (with the above sub-folders there too), but I don’t think it would normally be necessary.

The blog post Hannah linked to has an example application on GitHub that uses workers in Electron without any issue.

I know it's been a while but I wanted to touch back on this to provide what I ended up using as the solution.

As mentioned this is an Electron app and loading terrain locally was creating an issue because the method used to build the terrain, compressed all terrain data as gzipped .terrain files. When attempting to point Cesium to a local file, it doesn't know how to handle the gzipped files locally.

At the immediate time, I needed to get stuff working so I just made a basic local web server that did nothing but serve the terrain by setting the content-type: 'application/json' and content-encoding: 'gzip' response headers. This worked for a while but I really didn't want to have a local server just to have terrain.

I just recently removed the web server and have terrain loading locally by registering a custom protocol within Electron. By registering a custom stream protocol, I can make a my-app:// protocol and route to the appropriate path in the handler for it. In the protocol handler, you have the ability, in the callback, to specify response headers. This was the exact solution I needed allowing me to close an exposed port and load the data locally instead.