docs

Shipping Your App

Package desktop applications with runtime dependencies and configure settings for release distribution.

On this page

You can package a desktop application built in the Desktop Apps guides (starting with Building a Desktop App) into a standalone release that runs on machines without the SDK.

The release is a standalone folder on Windows and Linux— on macOS, it is an app bundle.

Packaging assumes the project links with the CMake package from Linking to the Library.

Distribute Runtime Files

An installed application needs runtime files placed alongside the executable— it cannot run from the compiled binary alone.

File Search Paths

The default file system loads file:/// URLs from the assets/ directory. Settings::file_system_path sets this root path and defaults to ./assets/.

On Windows and Linux, the path is relative to the folder containing the executable. Inside a macOS app bundle, the path is relative to Contents/Resources/.

The renderer loads its own runtime data from assets/resources/.

Required Files

Every release build requires the following files and directory layout:

Item Windows and Linux macOS App Bundle Contents
Shared libraries Beside the executable Contents/MacOS/ The four libraries from the SDK's bin/ folder (UltralightCore, WebCore, Ultralight, and AppCore).
SDK resources assets/resources/ Contents/Resources/assets/resources/ Runtime data including ICU data (icudt67l.dat), certificates (cacert.pem), and media controls.
Web content assets/ Contents/Resources/assets/ HTML, CSS, JavaScript, and image files for the page.
Web Inspector (optional) assets/inspector/ Contents/Resources/assets/inspector/ Web Inspector front end, included only when shipping developer tools to users.

🚧 Missing runtime resources

If an application runs from the build folder but fails once installed, the assets/resources/ folder is almost always missing. Without icudt67l.dat, App::Create() displays an error message box and exits. Without cacert.pem, the library logs an error and all HTTPS requests fail.

Package with CMake Install Rules

Calling find_package(Ultralight) defines path variables for the SDK's runtime files:

Windows and Linux Folders

Use CMake install() rules to assemble the executable and its runtime files into a standalone folder.

CMake
install(TARGETS MyApp RUNTIME DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/" DESTINATION "MyApp")
install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}" DESTINATION "MyApp/assets")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
        DESTINATION "MyApp/assets" OPTIONAL)

Running cmake --install populates the MyApp folder— ready to distribute directly or pass to an installer.

While ultralight_copy_runtime_files() from Linking to the Library stages these files in the build folder during development, install rules package them for release.

To ship developer tools to users, add an install rule that copies ULTRALIGHT_INSPECTOR_DIR into MyApp/assets.

macOS App Bundles

To target all three platforms in a single CMakeLists.txt, split the install rules with an if (APPLE) check.

CMake
if (APPLE)
  install(TARGETS MyApp BUNDLE DESTINATION ".")
  install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/"
          DESTINATION "MyApp.app/Contents/MacOS")
  install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}"
          DESTINATION "MyApp.app/Contents/Resources/assets")
  install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
          DESTINATION "MyApp.app/Contents/Resources/assets" OPTIONAL)
else ()
  install(TARGETS MyApp RUNTIME DESTINATION "MyApp")
  install(DIRECTORY "${ULTRALIGHT_BINARY_DIR}/" DESTINATION "MyApp")
  install(DIRECTORY "${ULTRALIGHT_RESOURCES_DIR}" DESTINATION "MyApp/assets")
  install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/"
          DESTINATION "MyApp/assets" OPTIONAL)
endif ()

For a complete example showing both layouts, see samples/cmake/Common.cmake in the SDK.

🚧 Set BUNDLE DESTINATION on macOS

A target configured with MACOSX_BUNDLE requires BUNDLE DESTINATION in its install(TARGETS) rule. Specifying RUNTIME DESTINATION alone causes a CMake configuration error on macOS.

Other Build Systems

Projects built without CMake must copy the runtime dependencies into the directory layouts shown above as a post-build step.

For step-by-step compiler and linker flags, see Linking to the Library.

The executable must be able to locate its shared libraries when launched. Windows searches the folder containing the executable automatically. On macOS, configure the linker to set the runtime search path (rpath) to @executable_path/. On Linux, set the rpath to $ORIGIN.

Configure Platform Settings

Each OS introduces release requirements beyond the build flags and link libraries described in Linking to the Library.

Windows

Target machines need the Microsoft Visual C++ Redistributable (x64)— an installer can bundle the package and run it during setup.

macOS

Pass MACOSX_BUNDLE to add_executable() to create an app bundle, then configure its properties in CMake.

CMake
set_target_properties(MyApp PROPERTIES
  MACOSX_BUNDLE_GUI_IDENTIFIER "com.acme.starlight"
  MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in")

CMake generates a default Info.plist for each bundle— you can point MACOSX_BUNDLE_INFO_PLIST at a custom template to override it. The SDK provides samples/cmake/Info.plist.in as a starting point to configure the bundle identifier, version string, and NSHighResolutionCapable.

The bundle identifier set in MACOSX_BUNDLE_GUI_IDENTIFIER also names the application's storage directories on macOS.

Linux

Target machines must meet the Linux system requirements, including the supported glibc version and the X11 and fontconfig libraries needed by libAppCore.so. For the required dependencies, see Linking to the Library.

Storage and Log Locations

Ultralight creates dedicated application directories to store runtime logs, profiler traces, and persistent session data like cookies and databases.

Directory paths are derived from Settings::developer_name and Settings::app_name, which default to "MyCompany" and "MyApp". Set these properties to your company and application names before calling App::Create().

Platform Session Data Logs and Traces
Windows %APPDATA%\<developer_name>\<app_name> Same folder as session data
macOS ~/Library/Application Support/<name> ~/Library/Caches/<name>
Linux $XDG_CACHE_HOME/com.<developer_name>.<app_name> Same folder as session data

On macOS, <name> is the bundle identifier, or com.<developer_name>.<app_name> when the bundle has none.

On Linux, the directory falls back to ~/.cache/com.<developer_name>.<app_name> if $XDG_CACHE_HOME is unset.

To configure custom storage paths, see Sessions and Site Data. For log output details, see Logging and Console Messages.

Prepare for Release

Before shipping an application, review runtime settings and test the packaged release on a clean machine.

App Settings in Settings

Settings is the first argument passed to App::Create().

Leave Settings::enable_profiler set to false, which is the default. Turning it on writes trace files on every run to the diagnostics folder rather than the session data folder— on macOS, this is ~/Library/Caches/<name>.

The profiler requires the Pro edition or higher.

Engine Options in Config

Config is the second argument passed to App::Create().

Keep Config::diagnostics.developer_mode set to false. When developer mode is off, a release library ignores diagnostics environment variables such as UL_JS_DIAGNOSTICS— users cannot alter runtime behavior from their environment. For details, see Developer Mode and Diagnostics.

🚧 Never ignore SSL errors in production

Keep Config::ignore_ssl_errors set to false, which is the default. Setting it to true connects to servers with invalid certificates, creating a security risk in production.

View Permissions in ViewConfig

Pass ViewConfig to Window::AddPanel() to configure settings for individual views.

Set ViewConfig::allow_universal_access_from_file_urls to false when you load local pages you don't fully control. The default value is true, which lets a file:/// page read other frames and send requests to any origin. Setting it to false enforces standard cross-origin rules for local files.

Test on a Clean Machine

Run the distributed application folder on a machine without the SDK or developer tools installed. This confirms that the executable finds its shared libraries and runtime files in their packaged locations.

Verify that assets/resources/ is present beside the executable— in a macOS app bundle, this belongs in Contents/Resources/assets/resources/.