Library / SDK
ThatOpen/engine_web-ifc avatar
ThatOpen/engine_web-ifc

ThatOpen/engine_web-ifc: reading and writing IFC files in the browser through WebAssembly

Reading and writing IFC files with Javascript, at native speeds.

1,072 stars289 forksTypeScriptMPL-2.0

At a glance

What is it?
web-ifc is an MPL-2.0 licensed JavaScript library that reads and writes IFC, the building information modelling interchange format, by compiling the C++ core to WebAssembly with Emscripten. The API is six lines long, but the build is not, and the README spends most of its length on Emscripten, CMake, SIMD, link time optimisation and how to build for a runtime without native WebAssembly exception handling.
Who is it for?
Adopt web-ifc if you need to open or author IFC models in a browser or in Node.js, because it brings a C++ IFC implementation to WebAssembly with SIMD and link time optimisation enabled, and the API surface is small enough to learn in an afternoon. Do not adopt it expecting a JavaScript IFC implementation you can read, since the parsing logic is compiled C++ behind a WASM boundary, so debugging it means building it with debugging information.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is

web-ifc is a JavaScript library to read and write IFC files, at native speeds, and it is part of the That Open Company project, which aims to lower the threshold for developing open BIM applications.

The technique is the interesting part. The heavy lifting is a C++ implementation of the IFC format, compiled to WebAssembly with Emscripten, and the JavaScript you import is a thin wrapper around that binary. That is why the README's quick setup is short and its build section is long, and it is the reason the library can claim native speeds in a browser, since the C++ code is running at close to the speed it would run natively, and the topics list gives the mechanism away with cpp, emscripten and webassembly alongside javascript and wasm.

The package is published to npm as `web-ifc`, with a demo at the project page, documentation for the library and for the wider platform, and a community site. The licence is MPL-2.0, which for a library that combines a JavaScript API with a compiled core is the permissive choice with a file level copyleft, so modifications to the covered files require those files to stay open.

The tree shows the split, with a `src/` directory holding the C++ core, the JavaScript API and a schema generator, `examples/` with a sample IFC file and a nodejs, usage and viewer example set, `tests/` with a public library of test models, a `Dockerfile` and the usual TypeScript configuration.

The API is six lines

The quick setup shows the whole surface, and it is worth noticing how little ceremony there is.

JavaScript
const WebIFC = require("web-ifc/web-ifc-api.js");

// initialize the API
const ifcApi = new WebIFC.IfcAPI();

// initialize the library
await ifcApi.Init();

// open a model from data
let modelID = ifcApi.OpenModel(/* IFC data as a string or UInt8Array */, /* optional settings object */, );

// the model is now loaded! use modelID to fetch geometry or properties
// checkout examples/usage for some details on how to read/write IFC

// close the model, all memory is freed
ifcApi.CloseModel(modelID);

So you construct an API object, initialise it asynchronously, open a model from either a string or a `UInt8Array`, and then use the model identifier to fetch geometry or properties. The final call closes the model and frees the memory, which is an explicit step rather than a garbage collected one, and that matters in a browser tab where a forgotten model is a few hundred megabytes of WebAssembly heap.

The installation is `npm install web-ifc`, and the entry point differs by environment, with the `exports` map in the package manifest pointing CommonJS and Node at the node API and `import` at the browser one, with the three WASM binaries exposed as subpath exports. The examples directory has separate folders for usage, nodejs and a viewer, and the repository has a `test.ifc` at the root for quick experiments.

The build is where the work is

The requirements for building your own version are Node v16 or later, NPM v7 or later, EMSCRIPTEN v4.0.23 or later and CMAKE v3.18 or later, plus MINGW on Windows.

The build sequence is spelled out. You install Emscripten and make sure `emsdk_env` is on your path, run `npm install` for the dependencies, and then run `npm run setup-env` whenever you open a new terminal, because that is the step that sets the emscripten environment variables you need to compile code. `npm run build-release` builds the release version of the WASM binary and the accompanying API into `./dist`, and `npm run build-debug` does the same with debugging information enabled, which the README says lets you inspect debugging information better when running web-ifc. And `npm run dev` launches a development server with a basic IFC file viewer.

What the release build enables is the part that matters for performance. Release builds enable SIMD and link-time optimization, along with native WebAssembly exception handling during both compilation and linking, and the stated benefit is that native exception handling reduces the code size and the runtime overhead of C++ exceptions on modern WebAssembly engines.

For a runtime without native exception support, you configure the existing build directory once with a specific command and then run the same release command:

sh
emcmake cmake -S src/cpp -B src/cpp/build_wasm -DEMSCRIPTEN=true -DCMAKE_BUILD_TYPE=Release -DWEB_IFC_WASM_NATIVE_EXCEPTIONS=OFF
npm run build-release

The option applies to the browser, Node and multithreaded targets, it defaults to on, and turning it off uses JavaScript based exception handling instead, with C++ exception catching remaining enabled in both modes and no effect on native C++ builds.

Eleven files leave the build

The build files section lists the output, and reading it tells you what the library actually ships.

There is `web-ifc.wasm`, the compiled C++ to run in the browser, `web-ifc-mt.wasm` for runtimes that support multi-threading, and `web-ifc-node.wasm` for Node. Then the JavaScript wrappers, `web-ifc-api-node.js` and `web-ifc-api.js`, each with a TypeScript definition file beside them. There is `ifc-schema.d.ts`, the TypeScript definitions for the IFC schema itself, and two helper definition files, `helpers/properties.d.ts` and `helpers/log.d.ts`, for the properties and logger aspects of the API. Finally there is `web-ifc-mt.worker.js`, the web worker script that enables multi-threading in the browser.

Two things are worth pulling out. The schema definitions are generated, and the `gen-schema` script runs a TypeScript generator in the schema generator directory, so the TypeScript types for the IFC schema are a build artefact rather than something maintained by hand. And the multi-threaded variant is a separate binary with its own worker, which is why the package exposes three WASM files rather than one, and why a consumer has to choose deliberately between the single threaded and multi threaded builds.

Regression testing against a library of models

For a library whose output is geometry, the test strategy is the interesting engineering decision, and it is a good one.

The project keeps a library of test models in the tests/public folder, and you can run the regression tests on all of these models with `npm run regression`. The behaviour is that it will alert you if any of the sample model geometry has changed, and if the change is correct you can refresh the regression tests with `npm run regression-update`.

So the tests are not assertions about expected values, they are a set of snapshots of what the library produced for a corpus of real models, and any difference is a prompt to look. For a parser whose output is a large mesh, that is the only practical way to notice a regression, because a hand written expected value for a building model is not something a person writes.

The project also asks for contributions. If you have a model you would like to contribute, please open a pull request, which means the test corpus grows with the community's models and the coverage improves with every contribution. There is a `benchmark.md` in the repository root as well, which is where the performance claims live.

The live build, the npm release, and the version puzzle

There is a third distribution channel, and it is the one to know about before you file a bug.

The current live build of web-ifc is available as a zip, and using it allows you to test the newest fixes before a release is made. To use it you download the zip and place the contents of the dist folder manually into your `node_modules/web-ifc` folder, and the README gives the nested case, since if you are using web-ifc-three then it is `node_modules/web-ifc-three/node_modules/web-ifc`. The instruction to note is that you must replace the JavaScript and the WASM.

That is a real operational hazard, because a project that silently mixes a newer WASM binary with an older wrapper is a project that will behave strangely. The instruction is explicit, and it is worth following to the letter.

The version numbering here is also worth reading carefully. The release tags are 0.76, 0.77 and 0.78, with 0.78 published on 2026-09-21, while the version in the package manifest is 0.0.79. So the npm version and the tag version do not move together, and the last push to the repository was on 2026-10-15 with the repository not archived. If you need to say precisely which build you are running, check both the tag and the manifest version, because they answer different questions.

Where web-ifc is the wrong choice

The first wrong case is a team that wants to read the IFC implementation. The parsing logic is C++ behind a WebAssembly boundary, so a stack trace from a malformed model is a WASM trace with no symbols unless you built it with debugging information yourself, and the README's build-debug section exists precisely because of that.

The second is a server side batch pipeline that does not need a browser. The project can be used stand-alone as a C++ library or executable, with a simple entry point in the C++ test directory, and that path skips the WebAssembly toolchain entirely, which is the right answer for a nightly conversion job. Reaching for the npm package in that situation means paying for Emscripten and a WASM runtime to do something a native build does better.

The third is an application that needs to author a model with rich geometry and everything that implies. The library does both reading and writing, but the writing side in the examples is about structure and metadata, and a full authoring tool is a much larger thing than a parser.

The fourth is a consumer that pins nothing. With a live build channel, an npm release and a manifest version that does not match the tag, the risk of running a mismatched pair is real, and the fix is to pin the npm version and verify the file hashes of the WASM binary you deploy.

On the state of the project, the releases are 0.76 in March 2026, 0.77 in March 2026 and 0.78 in September 2026, the repository is not archived, and the licence is MPL-2.0 with the `LICENSE.md` copied into the dist directory by the build, which is a small detail that means the licence travels with the artefact.

Editorial conclusion

Adopt web-ifc if you need to open or author IFC models in a browser or in Node.js, because it brings a C++ IFC implementation to WebAssembly with SIMD and link time optimisation enabled, and the API surface is small enough to learn in an afternoon. Do not adopt it expecting a JavaScript IFC implementation you can read, since the parsing logic is compiled C++ behind a WASM boundary, so debugging it means building it with debugging information. Verify first that the version you install includes the fixes you need, since the package version and the release tags move independently here, and if you build it yourself that you have Emscripten 4.0.23 or later and CMake 3.18 or later available, because those are the stated build requirements.

Frequently asked questions

What is web-ifc?

It is a JavaScript library for reading and writing IFC files at native speeds, implemented by compiling a C++ core to WebAssembly with Emscripten. It is part of the That Open Company project, which aims to lower the threshold for developing open BIM applications.

How do I read an IFC file with web-ifc?

Install the package with `npm install web-ifc`, require the API, create an `IfcAPI`, await `Init()`, then call `OpenModel` with the IFC data as a string or a `UInt8Array` and use the returned model identifier to fetch geometry or properties. Call `CloseModel` when you are done, which frees the memory.

What do I need to build web-ifc myself?

Node v16 or later, NPM v7 or later, Emscripten v4.0.23 or later and CMake v3.18 or later, plus MINGW on Windows. You put `emsdk_env` on your path, run `npm install`, run `npm run setup-env` in each new terminal, and then `npm run build-release` to produce the WASM binary and the API in the dist directory.

What does the web-ifc release build enable?

Release builds enable SIMD and link time optimization, together with native WebAssembly exception handling during compilation and linking, which reduces the code size and the runtime overhead of C++ exceptions on modern WebAssembly engines. You can turn that last one off with a build configuration flag for older runtimes.

How does web-ifc test for regressions?

The project keeps a library of test models in the tests/public folder, and `npm run regression` alerts you if the geometry of any sample model has changed, with `npm run regression-update` refreshing the snapshots when a change is correct. You can contribute a model by opening a pull request.

Official sources

  1. License: MPL-2.0
  2. Project website
  3. README
  4. Releases
  5. ThatOpen/engine_web-ifc on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/thatopen-engine-web-ifc.svg)](https://hysenlabs.com/projects/thatopen-engine-web-ifc)

Was this useful?