Zephyr implements a comprehensive dependency resolution system that enables micro-frontend applications to dynamically resolve and load their dependencies at build time, eliminating the need for hardcoded remote URLs and manual version coordination between teams.
In a micro-frontend architecture, applications are composed of multiple independent frontend modules that can be developed and deployed separately. Remote dependencies are other micro-frontend modules that your application needs to function - think of them as external components or services that your app imports and uses at runtime.
The dependency management system operates through a combination of build-time analysis and intelligent resolution strategies. During the build process, Zephyr plugins capture contextual information about the build environment and use this data to resolve abstract dependency declarations into concrete URLs and versions.
The resolution engine implements a multi-strategy approach to dependency resolution, attempting different resolution methods in a deterministic order until a valid dependency is found. Applications can adapt to various deployment scenarios without configuration changes.
Each resolution strategy is designed for specific use cases:
The system maintains backward compatibility while enabling advanced workflows that were previously difficult to implement in distributed architectures.
Before working with dependencies, it's essential to understand how Zephyr identifies applications. Every application has a unique Application UID following this structure:
Where:
name field from the remote application's package.jsonFor example, if you have:
package.json name: "ui-components"design-systemmy-companyThe Application UID would be: ui-components.design-system.my-company
Zephyr provides a dependency management system through the zephyr:dependencies field in your package.json to specify remote module federation dependencies that your application needs.
Add a zephyr:dependencies field to your package.json to specify remote applications your module depends on:
You will see more examples later in this guide
In the zephyr:dependencies configuration, there are three key concepts:
header, shoppingCart)ui-library, if they are in different repositories, use cart-service.repo-name.org-name)latest, stable, v2.1)The mapping works as follows:
The zephyr: prefix is optional. Both "ui-library@latest" and "zephyr:ui-library@latest" work identically, as zephyr is the default registry. While the prefix is currently optional, we recommend including it for future compatibility when Zephyr supports multiple registries (e.g., npm:, github:, or custom enterprise registries).
The zephyr:dependencies field serves to:
Zephyr's dependency resolution engine supports multiple version selector formats, each designed for specific use cases in your development and deployment workflows.
Version tags allow you to:
@latest, @stable, @next@v2.1, @release-3.0@production, @stagingFor more precise version control, Zephyr supports the full semver specification:
The selectors provide fine-grained control:
^1.2.3 - Compatible with version 1.2.3 (allows 1.x.x updates)~2.0.0 - Approximately equivalent to 2.0.0 (allows 2.0.x updates)1.5.0 - Exact version match only>=1.0.0 <2.0.0 - Any version within the specified rangeZephyr uses the official semver specification for version matching. When multiple versions match a range, the highest matching version is selected.
The wildcard "*" selector matches any available version of a dependency, similar to workspace:* but with different resolution behavior:
The "*" wildcard:
workspace:* when in developmentThe most powerful feature of Zephyr's dependency system is workspace resolution - the ability to automatically resolve dependencies based on your current build context:
When you use workspace:*, Zephyr intelligently resolves dependencies based on:
Feature branches automatically use matching versions of dependencies, eliminating the need for manual version updates during development.
In your code, you would import these as:
When depending on applications from different repositories or organizations, use the full Application UID format to avoid ambiguity:
Use the full UID format when:
The dependency resolution system leverages build context to enable dynamic version selection based on environmental factors. A single codebase can resolve to different dependency versions depending on the build environment, target platform, and deployment context.
The build context represents a structured collection of environmental metadata that the resolution engine uses to make deterministic version selections:
The Zephyr plugins automatically capture this context during the build initialization phase. The resolution engine then uses these values to select appropriate dependency versions through pattern matching and fallback chains.
The resolution engine implements platform-aware dependency selection, allowing applications to receive platform-optimized implementations of their dependencies:
The platform resolution follows a hierarchical approach:
The resolution engine implements automatic fallback to the 'web' platform when platform-specific versions are unavailable, ensuring build reliability while maintaining platform optimization when available.
Dependencies can also be resolved based on deployment environments and tags:
Zephyr will resolve these to the appropriate environment-specific versions, with automatic fallback to the default environment if the specified one doesn't exist.
The resolution engine processes dependency declarations through a deterministic pipeline of resolution strategies. Each strategy is attempted in order until a valid resolution is found or all strategies are exhausted.
Exact Version Match: If the selector specifies an exact version (e.g., 1.2.3), Zephyr looks for that specific version.
Workspace Resolution: For workspace:* selectors, Zephyr uses the build context to find matching versions based on branch, environment, and platform.
Semver Range Resolution: For semver selectors (e.g., ^1.0.0), Zephyr finds all matching versions and selects the highest one.
Label Resolution: For labeled versions (e.g., @latest, @stable), Zephyr resolves to the version tagged with that label.
Latest Version Fallback: If no specific version is found, Zephyr falls back to the latest available version.
Default Environment: As a final fallback, Zephyr checks the default environment for the application.
Applications must have at least one environment created in Zephyr Cloud to be resolvable as dependencies. Without an environment, resolution will fail. Create environments through the Zephyr dashboard after building your application.
During the build process, Zephyr:
zephyr:dependencies configurationResolved dependencies are cached during the build process to ensure consistency. If the same dependency is referenced multiple times, it will resolve to the same version throughout the build.
The resolution engine implements a multi-level fallback system to maximize resolution success rates:
Zephyr requires building applications in dependency order - the most distant remotes must be built first to accurately construct the dependency graph. When a dependency cannot be resolved, you'll see detailed error messages:
For applications using multiple remotes, unresolved dependencies will be listed together, helping you identify which applications need to be built first.
The following patterns and strategies optimize dependency resolution for different deployment scenarios and team workflows.
The workspace:* selector enables automatic local version coordination across branches:
The configuration enables:
For production deployments, combine different selectors for optimal stability:
The resolution system provides several mechanisms for troubleshooting dependency resolution failures:
When migrating existing applications to use advanced selectors:
You don't need to use all features at once. Start with basic version tags and gradually adopt more sophisticated selectors as your needs grow.
Monorepo Development:
Gradual Rollout: