Install SGLang from Source
Fork and clone the repository
Note: New contributors do not have the write permission to push to the official SGLang repo. Please fork the repository under your GitHub account, then clone your fork locally.Build from source
Refer to Install SGLang from Source.Format code with pre-commit
We use pre-commit to maintain consistent code style checks. Before pushing your changes, please run:pre-commit run --all-filesmanually runs all configured checks, applying fixes if possible. If it fails the first time, re-run it to ensure lint errors are fully resolved. Make sure your code passes all checks before creating a Pull Request.- Do not commit directly to the
mainbranch. Always create a new branch (e.g.,feature/my-new-feature), push your changes, and open a PR from that branch. - Documentation links and anchors are checked with Mintlify in CI. To run the same version locally, install it with
npm install -g mint@4.2.559, then runcd docs && mint broken-links --check-anchors --check-redirects. - The manual
lycheepre-commit hook checks links in the repository-levelREADME.md:pre-commit run --hook-stage manual lychee --all-files.
Run and add unit tests
If you add a feature or fix a bug, add focused regression coverage when the test protects a concrete behavior, invariant, or bookkeeping contract.Unit tests (no server required)
Unit tests live undertest/registered/unit/, organized to mirror the python/sglang/srt/ source tree. These tests validate component logic without launching a server or loading real model weights.
SGLang supports both Python’s built-in unittest framework and pytest. Registered CI tests must use CustomTestCase instead of raw unittest.TestCase, register themselves with register_*_ci(...), and include a standard __main__ entry point. CI discovers registrations with test/run_suite.py and executes each selected test file directly with fail-fast enabled.
When to add a unit test: If you modify a file under python/sglang/srt/, check whether a corresponding test exists in test/registered/unit/ and add coverage for your changes. For example:
Command
test/registered/unit/README.md.
E2E tests (server required)
For tests that require launching a server, refer totest/registered/README.md for guidance on where to place your test.
For detailed instructions on running tests and integrating them into CI, refer to test/README.md.
Write documentation
Documentation is a good way for new contributors to learn the SGLang codebase. See docs/README.md for the current Mintlify setup and validation commands.Test the accuracy
If your code changes model output, run an accuracy evaluation appropriate for the affected model and feature. For example, after launching a server, run the unified GSM8K evaluator:Benchmark the speed
Refer to Benchmark and Profiling.Requesting a review for merge
You can follow the pull request merge process described in MAINTAINER.md. You will need to work with the Merge Oncall, Codeowner, and other reviewers to get their approvals. Then your PR can be merged.How to Trigger CI Tests
We have a lot of open PRs but limited CI machines, so only top and trusted contributors have permission to trigger CI tests. Users with permission are listed in the CI_PERMISSIONS.json PR authors can use/rerun-failed-ci on their own PRs even if they are not listed in CI_PERMISSIONS.json. Selective reruns have additional rules because they execute PR code on self-hosted runners; see the permission table below.
For CI to run on a pull request, it must have the “run-ci” label. Authorized users can add the label or rerun failed tests by commenting on the PR with one of these commands:
/tag-run-ci-label: Adds the “run-ci” label. Only future commits trigger CI; the current commit is unaffected. Add theextraargument (/tag-run-ci-label extra) to additionally apply the “run-ci-extra” label, opting the PR into the extra test workflow (pr-test-extra.yml)./rerun-failed-ci: Reruns workflows from the latest commit with conclusion failed, skipped, cancelled, or timed out./tag-and-rerun-ci: Runs both. Use this on a fresh PR to kick off CI on the current commit —/tag-run-ci-labelalone won’t. Accepts the sameextraargument (/tag-and-rerun-ci extra)./rerun-test <test-spec> [<test-spec> ...]: Reruns one or more specific tests directly. A spec may select a file, class, or method using<file>::<TestClass>[.<test_method>]. Multiple specs and file globs are supported. Examples:/rerun-test test_srt_endpoint.py,/rerun-test registered/core/test_srt_endpoint.py::TestSRTEndpoint.test_simple_decode,/rerun-test test_a.py test_b.py, or/rerun-test test_*backend*.py./rerun-group <group> [<group> ...]: Expands one or more registered test groups (for example,/rerun-group hicache) and dispatches their tests through the same selective-rerun workflow.
If you have permission, the Slash Command Handler will run your command and react with a 👍 to your comment. It may take up to a few minutes for the reaction to appear. Here’s a usage example.
To avoid spamming a PR with too many
/rerun-failed-ci comments, you can also trigger the command by editing an existing comment and adding any suffix (e.g., /rerun-failed-ci try again).
If you don’t have permission and you’re not the PR author, please ask maintainers to trigger CI for you.
CI rate limits
Due to CI scheduling and limited resources, higher-priority PRs may preempt running jobs. In such cases, you may need to rerun the tests. We apply CI rate limits to prevent abuse and ensure fair usage of our CI resources. Each CI workflow has a default limit defined in its workflow configuration file. For example, in pr-gate.yml, the default cooldown period is 120 minutes, and each workflow can override it via thecool-down-minutes input parameter:
Config
Code style guidance
- Avoid code duplication. If the same code snippet (more than five lines) appears multiple times, extract it into a shared function.
- Minimize device synchronization. Reduce expensive CPU-GPU synchronization operations, such as
tensor.item()ortensor.cpu(), whenever possible. Use vectorized code. - Prioritize extreme efficiency. SGLang is a runtime, and most of your code runs on the critical path for every request. Optimize all minor overheads as much as possible, especially in the model forward code.
- A common pattern is some runtime checks in the model forward pass (e.g., this). These are very likely the same for every layer. Please cache the result as a single boolean value in
__init__whenever possible.
- A common pattern is some runtime checks in the model forward pass (e.g., this). These are very likely the same for every layer. Please cache the result as a single boolean value in
- Make functions as pure as possible. Avoid in-place modification of arguments.
- Prefer immutable data and compute configuration-derived values once during initialization when their inputs cannot change.
- Keep functions under roughly 100 lines and make orchestration functions read like high-level pseudocode by extracting details into focused helpers.
- Keep files concise. If a file exceeds 2,000 lines of code, split it into cohesive smaller modules.
- Avoid adding mixins; prefer composition or plain functions. Use
msgspec.Structfor new data containers instead ofdataclasses.dataclassorattrs. - Prefer keyword arguments for calls with two or more arguments, and pass callees the specific values they need instead of a large state-holding object.
- In a file, put core data structures at the top of the file. Put utility functions at the bottom of the file.
- Keep tests run fast.
- If a single test file runs longer than 500 seconds, split it into multiple smaller files (e.g.,
test_eagle_infer_a.py,test_eagle_infer_b.py). - If a single job in a GitHub Actions workflow runs longer than 30 minutes, split it into smaller jobs or steps.
- Reuse server launches across test methods in E2E test files.
- If a single test file runs longer than 500 seconds, split it into multiple smaller files (e.g.,
- Never use
pickle.loads(),pickle.load(), orrecv_pyobj()to deserialize untrusted or network-received data. Python’s pickle module is not secure — it can execute arbitrary code during deserialization. Use safe serialization formats such as msgpack or JSON instead. - When supporting new hardware or features, follow these guidelines:
- Do not drastically change existing code.
- Always prefer new files to introduce specific components for your new hardware (e.g.,
allocator_ascend.py). - If you write multiple if/else blocks for new features, ensure the common path (e.g., NVIDIA hardware or the existing code path) is the first branch.
How to update kernels in SGLang
Choose the implementation and release path based on the kernel’s dependencies. For a lightweight kernel that does not depend on CUTLASS or another large C++ project, prefer the in-tree JIT kernel path. Use the AOTsglang-kernel path for heavyweight kernels, large C++ dependencies, or operations that need wheel packaging and Torch operator registration. FlashInfer-based kernels are an exception and may still use the JIT path. SGLang also consumes separately released custom builds of DeepGEMM and DeepEP; update those in their source repositories as described below.
Update sglang-kernel
Thesglang-kernel distribution (formerly sgl-kernel) is a separate Python package, but its source now lives in this repository under python/sglang/kernels/aot/. Normal PR CI builds and installs a PR-local sglang-kernel wheel, so it can test an AOT kernel and its caller together. This does not establish compatibility after merge: installed SGLang and scheduled CI use the released version pinned in python/pyproject.toml. If a caller unconditionally requires a new operator or a changed kernel contract, first merge and release the kernel, update the pinned sglang-kernel version, and then land the caller. A combined PR is acceptable only when every supported path remains correct with the pinned wheel—for example, when the caller checks operator availability and retains a semantically equivalent fallback until the released wheel includes the change. Selective /rerun-test and /rerun-group workflows do not install PR-local wheels and cannot validate the combined AOT path.
For an AOT kernel change:
- Implement the kernel under
python/sglang/kernels/aot/csrc/and update its declaration, Torch registration, and CMake source list. - Expose the Python API under
python/sglang/kernels/aot/python/sgl_kernel/. - Add correctness tests under
python/sglang/kernels/aot/tests/and a benchmark underpython/sglang/kernels/aot/benchmark/when applicable. - Build and test from
python/sglang/kernels/aot/following its README. Do not bump the pinnedsglang-kernelversion inpython/pyproject.tomlmerely to test a PR-local kernel change.
Update sgl-deep-gemm
Develop SGLang’s customized DeepGEMM package on thedev branch of sgl-project/DeepGEMM. Rebase incoming changes onto dev, place new or modified package tests under sgl_deep_gemm/tests/, and follow the sgl-deep-gemm README to build and install a local wheel. After the implementation is merged, ask the SGLang team to run the sgl-deep-gemm release workflow with the new version, CUDA target, and DeepGEMM branch. Once all required wheels are published and verified, update the sgl-deep-gemm pin in python/pyproject.toml before landing SGLang code that requires the new or changed behavior.
Update sgl-deep-ep
Developsgl-deep-ep in sgl-project/DeepEP. Use the implementation branch for the target platform: sgl-deepep for CUDA 13 on x86_64 or aarch64, sgl-deepep-cu12-x86 for CUDA 12.9 on x86_64, or sgl-deepep-cu12-arm for CUDA 12.9 on aarch64. Merge packaging changes into sgl-deepep-packaging. The sgl-deep-ep README describes the platform prerequisites and release matrix.
To validate locally, check out the selected implementation branch as DeepEP-source and the packaging branch as DeepEP-packaging. Install the required build dependencies first; CUDA 12.9 builds also require GDRCopy. The following CUDA 13 example builds a wheel for the host architecture, installs that exact wheel, and verifies that its guarded package import succeeds:
12.9 instead of 13.0 for a CUDA 12.9 build. The import check validates packaging and binary loading, but not communication correctness. On a configured multi-GPU host, also run the test appropriate for the implementation branch:
--num-processes to the available GPUs and run the internode or low-latency tests when those transports changed. After local validation, ask the SGLang team to run the sgl-deep-ep release workflow with the new version, CUDA target, and packaging ref. After verifying the published wheels for the supported Python versions and architectures, update the sgl-deep-ep pin in python/pyproject.toml before landing dependent SGLang changes.
Tips for newcomers
If you want to contribute but don’t have a specific idea in mind, pick issues labeled “good first issue” or “help wanted”. These tasks typically have lower complexity and provide an excellent introduction to the codebase. Also check out the following materials as startup guide:- Mini-SGLang for a quick overview on the structure of sglang.
- Code Walk-through for a deeper look into SGLang’s workflow.
- GTC-2026 Training Lab for hands-on practices of how to do optimization, benchmarking, or profiling on a launched SGLang instance.
