| --- |
| title: "Building Dynamically Linked Bifrost Binary" |
| description: "Learn how to build a dynamically linked Bifrost binary required for custom plugin support" |
| icon: "hammer" |
| --- |
|
|
| ## Why Dynamic Linking? |
|
|
| Go |
|
|
| To use custom plugins with Bifrost, you must build a dynamically linked binary that links against the system |
|
|
| <Warning> |
| Dynamic plugins only work on **Linux** and **macOS** (Darwin). Windows is not supported by Go |
| </Warning> |
|
|
| ## Static vs Dynamic Builds |
|
|
| ### Static Builds (Default) |
|
|
| Bifrost |
|
|
| ```bash |
| go build \ |
| -ldflags="-w -s -extldflags '-static' -X main.Version=v1.3.30" \ |
| -tags "sqlite_static" \ |
| -o bifrost-http |
| ``` |
|
|
| **Characteristics:** |
| - ✅ Portable across all Linux distributions (musl, glibc, etc.) |
| - ✅ No external dependencies required at runtime |
| - ✅ Smaller deployment surface area |
| - ❌ **Cannot load Go plugins** |
|
|
| **Use static builds when:** You don |
|
|
| ### Dynamic Builds (For Plugins) |
|
|
| To enable plugin support, build without static linking flags: |
|
|
| ```bash |
| go build \ |
| -ldflags="-w -s -X main.Version=v1.3.30" \ |
| -o bifrost-http |
| ``` |
|
|
| **Characteristics:** |
| - ✅ **Can load Go plugins** (`.so` files) |
| - ✅ Slightly faster compilation |
| - ⚠️ Must match the target system |
| - ⚠️ Less portable across different Linux distributions |
|
|
| **Use dynamic builds when:** You need custom plugin support. |
|
|
| ## Building with Makefile |
|
|
| The easiest way to build a dynamic binary is using the `DYNAMIC=1` flag with the Makefile: |
|
|
| ### Local Build |
|
|
| ```bash |
| # Build dynamically linked binary for your current platform |
| make build DYNAMIC=1 |
|
|
| # With version tag |
| make build DYNAMIC=1 VERSION=1.3.30 |
| ``` |
|
|
| This creates `tmp/bifrost-http` as a dynamically linked binary. |
|
|
| ### Cross-Compilation |
|
|
| ```bash |
| # Build for Linux AMD64 (uses Docker if cross-compiling) |
| make build DYNAMIC=1 GOOS=linux GOARCH=amd64 |
|
|
| # Build for Linux ARM64 |
| make build DYNAMIC=1 GOOS=linux GOARCH=arm64 |
| ``` |
|
|
| ### How It Works |
|
|
| The `DYNAMIC=1` flag automatically: |
| - ✅ Removes `-extldflags "-static"` from ldflags |
| - ✅ Removes `-tags "sqlite_static"` build tag |
| - ✅ Keeps `CGO_ENABLED=1` (required for SQLite and plugins) |
| - ✅ Uses Docker for cross-compilation when needed |
|
|
| ## Building with Docker |
|
|
| For containerized deployments, you |
|
|
| ### Option A: Alpine Linux (musl libc) |
|
|
| Use this for Alpine-based deployments or when you want minimal image size. |
|
|
| <Accordion title="Complete Dockerfile for Alpine (musl libc)"> |
|
|
| ```dockerfile |
| # --- UI Build Stage: Build the Next.js frontend --- |
| FROM node:25-alpine3.23 AS ui-builder |
| WORKDIR /app |
|
|
| # Copy UI package files and install dependencies |
| COPY ui/package*.json ./ |
| RUN npm ci |
|
|
| # Copy UI source code |
| COPY ui/ ./ |
|
|
| # Build UI (skip the copy-build step) |
| RUN npx next build |
| RUN node scripts/fix-paths.js |
|
|
| # --- Go Build Stage: Compile the Go binary --- |
| FROM golang:1.26.1-alpine3.23 AS builder |
| WORKDIR /app |
|
|
| # Install dependencies including gcc for CGO and sqlite |
| RUN apk add --no-cache gcc musl-dev sqlite-dev |
|
|
| # Set environment for CGO-enabled build (required for go-sqlite3 and plugins) |
| ENV CGO_ENABLED=1 GOOS=linux |
|
|
| COPY transports/go.mod transports/go.sum ./ |
| RUN go mod download |
|
|
| # Copy source code and dependencies |
| COPY transports/ ./ |
|
|
| COPY --from=ui-builder /app/out ./bifrost-http/ui |
|
|
| # Build the binary with CGO enabled for DYNAMIC LINKING |
| ENV GOWORK=off |
| ARG VERSION=unknown |
| RUN go build \ |
| -ldflags="-w -s -X main.Version=v${VERSION}" \ |
| -a -trimpath \ |
| -o /app/main \ |
| ./bifrost-http |
|
|
| # Verify build succeeded |
| RUN test -f /app/main || (echo "Build failed" && exit 1) |
|
|
| # --- Runtime Stage: Minimal runtime image --- |
| FROM alpine:3.23 |
| WORKDIR /app |
|
|
| # Install runtime dependencies for CGO-enabled dynamic binary |
| # musl: C standard library (required for CGO binaries) |
| # libgcc: GCC runtime library |
| # ca-certificates: For HTTPS connections |
| # wget: For healthcheck |
| RUN apk add --no-cache musl libgcc ca-certificates wget |
|
|
| # Create data directory and set up user |
| COPY --from=builder /app/main . |
| COPY --from=builder /app/docker-entrypoint.sh . |
|
|
| # Getting arguments |
| ARG ARG_APP_PORT=8080 |
| ARG ARG_APP_HOST=0.0.0.0 |
| ARG ARG_LOG_LEVEL=info |
| ARG ARG_LOG_STYLE=json |
| ARG ARG_APP_DIR=/app/data |
|
|
| # Environment variables with defaults (can be overridden at runtime) |
| ENV APP_PORT=$ARG_APP_PORT \ |
| APP_HOST=$ARG_APP_HOST \ |
| LOG_LEVEL=$ARG_LOG_LEVEL \ |
| LOG_STYLE=$ARG_LOG_STYLE \ |
| APP_DIR=$ARG_APP_DIR |
|
|
| RUN mkdir -p $APP_DIR/logs && \ |
| adduser -D -s /bin/sh appuser && \ |
| chown -R appuser:appuser /app && \ |
| chmod +x /app/docker-entrypoint.sh |
| USER appuser |
|
|
| # Declare volume for data persistence |
| VOLUME ["/app/data"] |
| EXPOSE $APP_PORT |
|
|
| # Health check for container status monitoring |
| HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ |
| CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${APP_PORT}/metrics || exit 1 |
|
|
| # Use entrypoint script that handles volume permissions and argument processing |
| ENTRYPOINT ["/app/docker-entrypoint.sh"] |
| CMD ["/app/main"] |
| ``` |
|
|
| </Accordion> |
|
|
| **Key changes from static build:** |
| - Line 40-44: Removed `-extldflags |
| - Removed UPX compression step (optional, but simpler) |
| - Runtime uses musl libc from Alpine base image |
|
|
| **Build and run:** |
|
|
| ```bash |
| # Build the image |
| docker build -f transports/Dockerfile -t bifrost:dynamic-alpine . |
|
|
| # Run the container |
| docker run -p 8080:8080 -v ./plugins:/app/data/plugins bifrost:dynamic-alpine |
| ``` |
|
|
| ### Option B: Debian (glibc) |
|
|
| Use this for Debian/Ubuntu-based deployments or when deploying to glibc-based systems. |
|
|
| <Accordion title="Complete Dockerfile for Debian (glibc)"> |
|
|
| ```dockerfile |
| # --- UI Build Stage: Build the Next.js frontend --- |
| FROM node:25-bookworm AS ui-builder |
| WORKDIR /app |
|
|
| # Copy UI package files and install dependencies |
| COPY ui/package*.json ./ |
| RUN npm ci |
|
|
| # Copy UI source code |
| COPY ui/ ./ |
|
|
| # Build UI |
| RUN npx next build |
| RUN node scripts/fix-paths.js |
|
|
| # --- Go Build Stage: Compile the Go binary --- |
| FROM golang:1.26.1-bookworm AS builder |
| WORKDIR /app |
|
|
| # Install dependencies including gcc for CGO and sqlite |
| RUN apt-get update && apt-get install -y \ |
| gcc \ |
| libc6-dev \ |
| libsqlite3-dev \ |
| && rm -rf /var/lib/apt/lists/* |
|
|
| # Set environment for CGO-enabled build (required for go-sqlite3 and plugins) |
| ENV CGO_ENABLED=1 GOOS=linux |
|
|
| COPY transports/go.mod transports/go.sum ./ |
| RUN go mod download |
|
|
| # Copy source code and dependencies |
| COPY transports/ ./ |
|
|
| COPY --from=ui-builder /app/out ./bifrost-http/ui |
|
|
| # Build the binary with CGO enabled for DYNAMIC LINKING |
| ENV GOWORK=off |
| ARG VERSION=unknown |
| RUN go build \ |
| -ldflags="-w -s -X main.Version=v${VERSION}" \ |
| -a -trimpath \ |
| -o /app/main \ |
| ./bifrost-http |
|
|
| # Verify build succeeded |
| RUN test -f /app/main || (echo "Build failed" && exit 1) |
|
|
| # --- Runtime Stage: Minimal runtime image --- |
| FROM debian:bookworm-slim |
| WORKDIR /app |
|
|
| # Install runtime dependencies for CGO-enabled dynamic binary |
| # libc6: GNU C Library (required for glibc-linked binaries) |
| # ca-certificates: For HTTPS connections |
| RUN apt-get update && apt-get install -y \ |
| libc6 \ |
| ca-certificates \ |
| wget \ |
| && rm -rf /var/lib/apt/lists/* |
|
|
| # Create data directory and set up user |
| COPY --from=builder /app/main . |
| COPY --from=builder /app/docker-entrypoint.sh . |
|
|
| # Getting arguments |
| ARG ARG_APP_PORT=8080 |
| ARG ARG_APP_HOST=0.0.0.0 |
| ARG ARG_LOG_LEVEL=info |
| ARG ARG_LOG_STYLE=json |
| ARG ARG_APP_DIR=/app/data |
|
|
| # Environment variables with defaults (can be overridden at runtime) |
| ENV APP_PORT=$ARG_APP_PORT \ |
| APP_HOST=$ARG_APP_HOST \ |
| LOG_LEVEL=$ARG_LOG_LEVEL \ |
| LOG_STYLE=$ARG_LOG_STYLE \ |
| APP_DIR=$ARG_APP_DIR |
|
|
| RUN mkdir -p $APP_DIR/logs && \ |
| useradd -m -s /bin/sh appuser && \ |
| chown -R appuser:appuser /app && \ |
| chmod +x /app/docker-entrypoint.sh |
| USER appuser |
|
|
| # Declare volume for data persistence |
| VOLUME ["/app/data"] |
| EXPOSE $APP_PORT |
|
|
| # Health check for container status monitoring |
| HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ |
| CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${APP_PORT}/metrics || exit 1 |
|
|
| # Use entrypoint script that handles volume permissions and argument processing |
| ENTRYPOINT ["/app/docker-entrypoint.sh"] |
| CMD ["/app/main"] |
| ``` |
|
|
| </Accordion> |
|
|
| **Key differences from Alpine version:** |
| - Uses `bookworm` (Debian 12) base images instead of Alpine |
| - Installs `apt` packages instead of `apk` |
| - Runtime uses glibc (libc6) instead of musl |
| - Uses `useradd` instead of `adduser` for user creation |
|
|
| **Build and run:** |
|
|
| ```bash |
| # Build the image |
| docker build -f transports/Dockerfile.debian -t bifrost:dynamic-debian . |
|
|
| # Run the container |
| docker run -p 8080:8080 -v ./plugins:/app/data/plugins bifrost:dynamic-debian |
| ``` |
|
|
| ## libc Compatibility |
|
|
| Understanding libc (C standard library) compatibility is **critical** when building dynamic binaries and plugins. |
|
|
| ### musl vs glibc |
|
|
| Linux distributions use one of two main C standard libraries: |
|
|
| | libc Type | Used By | Characteristics | |
| |-----------|---------|-----------------| |
| | **musl** | Alpine Linux | Lightweight, minimal, security-focused | |
| | **glibc** | Debian, Ubuntu, RHEL, CentOS, Fedora, Amazon Linux | Standard GNU C Library, feature-rich | |
|
|
| ### The Golden Rule |
|
|
| <Warning> |
| - **A binary built with musl will NOT run on glibc systems.** |
| - **A binary built with glibc will NOT run on musl systems.** |
| - **Plugins and Bifrost MUST use the same libc.** |
| </Warning> |
|
|
| ### Why This Matters |
|
|
| When you build a dynamic binary: |
|
|
| ```bash |
| # Built on Alpine (musl) |
| $ ldd bifrost-http |
| linux-vdso.so.1 |
| libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 |
|
|
| # Built on Debian (glibc) |
| $ ldd bifrost-http |
| linux-vdso.so.1 |
| libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 |
| ``` |
|
|
| The binary is linked to a **specific** libc implementation. If you try to run it on a system with a different libc, you |
|
|
| ``` |
| error while loading shared libraries: libc.musl-x86_64.so.1: cannot open shared object file |
| ``` |
|
|
| ### Choosing Your Build Environment |
|
|
| **Decision Matrix:** |
|
|
| | Target Deployment | Build With | Dockerfile Base | |
| |-------------------|------------|-----------------| |
| | Alpine containers | musl | `golang:1.26.1-alpine3.23` | |
| | Debian/Ubuntu containers | glibc | `golang:1.26.1-bookworm` | |
| | Ubuntu/Debian servers | glibc | `golang:1.26.1-bookworm` | |
| | RHEL/CentOS servers | glibc | Native build or glibc container | |
| | Kubernetes (Alpine) | musl | `golang:1.26.1-alpine3.23` | |
| | Kubernetes (Debian) | glibc | `golang:1.26.1-bookworm` | |
|
|
| **Simple rule:** Build with the same base OS family as your deployment target. |
|
|
| ### Building Plugins |
|
|
| Plugins **must** be built with the **exact same environment** as your Bifrost binary: |
|
|
| ```bash |
| # If Bifrost was built with Alpine/musl |
| docker run --rm \ |
| -v "$PWD:/work" \ |
| -w /work \ |
| golang:1.26.1-alpine3.23 \ |
| sh -c "apk add --no-cache gcc musl-dev && \ |
| go build -buildmode=plugin -o myplugin.so main.go" |
|
|
| # If Bifrost was built with Debian/glibc |
| docker run --rm \ |
| -v "$PWD:/work" \ |
| -w /work \ |
| golang:1.26.1-bookworm \ |
| sh -c "apt-get update && apt-get install -y gcc && \ |
| go build -buildmode=plugin -o myplugin.so main.go" |
| ``` |
|
|
| See the [hello-world plugin Makefile](https://github.com/maximhq/bifrost/blob/main/examples/plugins/hello-world/Makefile) for a complete example. |
|
|
| ## Verification |
|
|
| ### Verify Dynamic Linking |
|
|
| After building, check that your binary is dynamically linked: |
|
|
| ```bash |
| # Check binary dependencies |
| ldd tmp/bifrost-http |
|
|
| # Expected output (musl): |
| linux-vdso.so.1 |
| libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 |
|
|
| # Expected output (glibc): |
| linux-vdso.so.1 |
| libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 |
| libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 |
| ``` |
|
|
| If you see `statically linked`, the binary **will not load plugins**. |
|
|
| ### Verify Plugin Compatibility |
|
|
| Test that your plugin loads successfully: |
|
|
| ```bash |
| # Start Bifrost with your plugin configured |
| ./tmp/bifrost-http -config config.json |
|
|
| # Check logs for plugin initialization |
| # Should see: "Plugin loaded successfully: your-plugin-name" |
| ``` |
|
|
| ## Go Version and Package Compatibility |
|
|
| ### Go Version Requirement |
|
|
| Bifrost is built with **Go 1.26.1**. Your plugin **must** be compiled with the exact same Go version to ensure compatibility. |
|
|
| ```bash |
| # Check your Go version |
| go version |
| # Should output: go version go1.26.1 ... |
|
|
| # If you need to install Go 1.26.1 |
| # Visit: https://go.dev/dl/ |
| ``` |
|
|
| ### Key Package Versions |
|
|
| Bifrost uses the following key packages across its three main modules that may affect plugin development: |
|
|
| #### Transport Layer (`transports/go.mod`) |
|
|
| | Package | Version | Purpose | |
| |---------|---------|---------| |
| | `github.com/bytedance/sonic` | v1.14.1 | High-performance JSON serialization | |
| | `github.com/valyala/fasthttp` | v1.67.0 | Fast HTTP server/client | |
| | `github.com/fasthttp/router` | v1.5.4 | HTTP router for fasthttp | |
| | `github.com/fasthttp/websocket` | v1.5.12 | WebSocket support | |
| | `github.com/prometheus/client_golang` | v1.23.0 | Prometheus metrics | |
| | `gorm.io/gorm` | v1.31.1 | Database ORM | |
|
|
| #### Core Layer (`core/go.mod`) |
|
|
| | Package | Version | Purpose | |
| |---------|---------|---------| |
| | `github.com/bytedance/sonic` | v1.14.1 | High-performance JSON serialization | |
| | `github.com/valyala/fasthttp` | v1.67.0 | Fast HTTP client for providers | |
| | `github.com/google/uuid` | v1.6.0 | UUID generation | |
| | `github.com/rs/zerolog` | v1.34.0 | Zero-allocation JSON logger | |
| | `github.com/mark3labs/mcp-go` | v0.41.1 | Model Context Protocol support | |
| | `golang.org/x/oauth2` | v0.32.0 | OAuth2 client | |
|
|
| #### Framework Layer (`framework/go.mod`) |
|
|
| | Package | Version | Purpose | |
| |---------|---------|---------| |
| | `github.com/redis/go-redis/v9` | v9.14.0 | Redis client for caching | |
| | `github.com/weaviate/weaviate-go-client/v5` | v5.5.0 | Weaviate vector store client | |
| | `github.com/mattn/go-sqlite3` | v1.14.32 | SQLite3 driver (requires CGO) | |
| | `gorm.io/gorm` | v1.31.1 | Database ORM | |
| | `gorm.io/driver/sqlite` | v1.6.0 | GORM SQLite driver | |
| | `gorm.io/driver/postgres` | v1.6.0 | GORM PostgreSQL driver | |
| | `golang.org/x/crypto` | v0.43.0 | Cryptographic functions | |
|
|
| <Note> |
| If your plugin imports any of these packages, use compatible versions to avoid runtime issues. Check `transports/go.mod`, `core/go.mod`, and `framework/go.mod` for complete dependency lists. |
| </Note> |
|
|
| ### Checking Bifrost |
|
|
| To see all dependencies used by Bifrost across its three main modules: |
|
|
| ```bash |
| # View transport layer dependencies |
| cat transports/go.mod |
|
|
| # View core dependencies |
| cat core/go.mod |
|
|
| # View framework dependencies |
| cat framework/go.mod |
|
|
| # Or list all dependencies for a specific module |
| cd transports && go list -m all |
| cd ../core && go list -m all |
| cd ../framework && go list -m all |
| ``` |
|
|
| ### Plugin go.mod Example |
|
|
| When creating a plugin, your `go.mod` should match Bifrost |
|
|
| ```go |
| module github.com/example/my-plugin |
|
|
| go 1.26.1 |
|
|
| require ( |
| github.com/maximhq/bifrost/core v1.2.38 |
| // Optional: Add framework for advanced features |
| // github.com/maximhq/bifrost/framework v1.1.48 |
| |
| // Add other dependencies as needed, matching versions from Bifrost |
| // github.com/bytedance/sonic v1.14.1 |
| // github.com/rs/zerolog v1.34.0 |
| ) |
| ``` |
|
|
| <Tip> |
| Import only the Bifrost modules you need. Most plugins only require `core`. Use `framework` if you need access to config stores, vector stores, or other framework features. |
| </Tip> |
|
|
| ## Troubleshooting |
|
|
| ### Common Errors |
|
|
| #### 1. Cannot load plugin - Go version mismatch |
|
|
| ``` |
| cannot load plugin: plugin was built with a different version of package runtime/internal/sys |
| ``` |
|
|
| **Cause:** Plugin and Bifrost were built with different Go versions. |
|
|
| **Solution:** Use the exact same Go version (Go 1.26.1) for both: |
|
|
| ```bash |
| # Check Go version used for Bifrost |
| ./tmp/bifrost-http -version |
|
|
| # Verify your Go version matches |
| go version # Should output: go version go1.26.1 |
|
|
| # See full compatibility requirements |
| ``` |
|
|
| Refer to [Go Version and Package Compatibility](#go-version-and-package-compatibility) for details. |
|
|
| #### 2. Shared library not found |
|
|
| ``` |
| error while loading shared libraries: libc.musl-x86_64.so.1: cannot open shared object file |
| ``` |
|
|
| **Cause:** Binary built with musl trying to run on glibc system (or vice versa). |
|
|
| **Solution:** Rebuild with the correct libc for your target system. |
|
|
| #### 3. Plugin architecture mismatch |
|
|
| ``` |
| plugin was built with a different version of package internal/cpu |
| ``` |
|
|
| **Cause:** Plugin and Bifrost built for different architectures (amd64 vs arm64). |
|
|
| **Solution:** Ensure `GOARCH` matches for both builds: |
|
|
| ```bash |
| # Check architecture |
| uname -m # x86_64 = amd64, aarch64 = arm64 |
|
|
| # Build with explicit architecture |
| GOARCH=amd64 go build ... |
| ``` |
|
|
| #### 4. Plugin file not found |
|
|
| ``` |
| plugin.Open("myplugin.so"): realpath failed: no such file or directory |
| ``` |
|
|
| **Cause:** Plugin file path is incorrect in config. |
|
|
| **Solution:** Use absolute paths or verify relative paths: |
|
|
| ```json |
| { |
| "plugins": [ |
| { |
| "path": "/app/data/plugins/myplugin.so", |
| "config": {} |
| } |
| ] |
| } |
| ``` |
|
|
| ## Best Practices |
|
|
| ### 1. Document Your Build Environment |
|
|
| Create a `BUILD.md` file documenting: |
| - Go version used |
| - Base image (Alpine vs Debian) |
| - Build commands |
| - Target deployment platform |
|
|
| ### 2. Use Consistent Tooling |
|
|
| Match Bifrost |
|
|
| ```bash |
| # Pin Go version in Dockerfile |
| FROM golang:1.26.1-alpine3.23 AS builder |
|
|
| # Pin Go version in Makefile/CI |
| GO_VERSION=1.26.1 |
| ``` |
|
|
| ### 3. Test Plugin Loading Locally |
|
|
| Before deploying, test plugin loading: |
|
|
| ```bash |
| # Build both Bifrost and plugin |
| make build DYNAMIC=1 |
| cd examples/plugins/hello-world && make build |
|
|
| # Test loading |
| ./tmp/bifrost-http -config examples/plugins/hello-world/config.json |
| ``` |
|
|
| ### 4. Version Your Plugins |
|
|
| Tag plugin builds with version and build info: |
|
|
| ```bash |
| go build -buildmode=plugin \ |
| -ldflags="-X main.Version=v1.0.0 -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ |
| -o myplugin-v1.0.0.so |
| ``` |
|
|
| ### 5. Multi-Stage Dockerfiles for Plugins |
|
|
| Build plugins in the same Dockerfile as Bifrost: |
|
|
| ```dockerfile |
| # Build plugin |
| FROM golang:1.26.1-alpine3.23 AS plugin-builder |
| WORKDIR /plugin |
| COPY plugins/myplugin/ . |
| RUN apk add --no-cache gcc musl-dev && \ |
| go build -buildmode=plugin -o myplugin.so main.go |
|
|
| # Build Bifrost |
| FROM golang:1.26.1-alpine3.23 AS bifrost-builder |
| # ... (bifrost build steps) |
|
|
| # Runtime |
| FROM alpine:3.23 |
| COPY --from=bifrost-builder /app/main . |
| COPY --from=plugin-builder /plugin/myplugin.so /app/plugins/ |
| ``` |
|
|
| This ensures plugins and Bifrost use identical build environments. |
|
|
| ## Next Steps |
|
|
| Now that you have a dynamically linked Bifrost binary: |
|
|
| 1. **[Write your first plugin](./writing-plugin)** - Learn the plugin API and create custom functionality |
| 2. **[Deploy with plugins](../deployment-guides)** - Best practices for production deployments |
| 3. **[Example plugins](https://github.com/maximhq/bifrost/tree/main/examples/plugins)** - Study working examples |
|
|
| <Note> |
| For questions or issues with dynamic builds and plugins, visit our [GitHub Discussions](https://github.com/maximhq/bifrost/discussions) or [Discord community](https://discord.gg/exN5KAydbU). |
| </Note> |
|
|
|
|