# Non-Cargo Based Projects

rust-analyzer does not require Cargo. However, if you use some other build system, you’ll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format:

    interface JsonProject {
        /// Path to the sysroot directory.
        ///
        /// The sysroot is where rustc looks for the
        /// crates that are built-in to rust, such as
        /// std.
        ///
        /// https://doc.rust-lang.org/rustc/command-line-arguments.html#--sysroot-override-the-system-root
        ///
        /// To see the current value of sysroot, you
        /// can query rustc:
        ///
        /// ```
        /// $ rustc --print sysroot
        /// /Users/yourname/.rustup/toolchains/stable-x86_64-apple-darwin
        /// ```
        sysroot?: string;
        /// Path to the directory with *source code* of
        /// sysroot crates.
        ///
        /// By default, this is `lib/rustlib/src/rust/library`
        /// relative to the sysroot.
        ///
        /// It should point to the directory where std,
        /// core, and friends can be found:
        ///
        /// https://github.com/rust-lang/rust/tree/master/library.
        ///
        /// If provided, rust-analyzer automatically adds
        /// dependencies on sysroot crates. Conversely,
        /// if you omit this path, you can specify sysroot
        /// dependencies yourself and, for example, have
        /// several different "sysroots" in one graph of
        /// crates.
        sysroot_src?: string;
        /// List of groups of common cfg values, to allow
        /// sharing them between crates.
        ///
        /// Maps from group name to its cfgs. Cfg follow
        /// the same format as `Crate.cfg`.
        cfg_groups?: { [key: string]: string[]; };
        /// The set of crates comprising the current
        /// project. Must include all transitive
        /// dependencies as well as sysroot crate (libstd,
        /// libcore and such).
        crates: Crate[];
        /// Configuration for CLI commands.
        ///
        /// These are used for running and debugging binaries
        /// and tests without encoding build system-specific
        /// knowledge into rust-analyzer.
        ///
        /// # Example
        ///
        /// Below is an example of a test runnable. `{label}` and `{test_id}`
        /// are explained in `Runnable::args`'s documentation below.
        ///
        /// ```json
        /// {
        ///     "program": "buck",
        ///     "args": [
        ///         "test",
        ///          "{label}",
        ///          "--",
        ///          "{test_id}",
        ///          "--print-passing-details"
        ///     ],
        ///     "cwd": "/home/user/repo-root/",
        ///     "kind": "testOne"
        /// }
        /// ```
        runnables?: Runnable[];
    }

    interface Crate {
        /// Optional crate name used for display purposes,
        /// without affecting semantics. See the `deps`
        /// key for semantically-significant crate names.
        display_name?: string;
        /// Path to the root module of the crate.
        root_module: string;
        /// Edition of the crate.
        edition: '2015' | '2018' | '2021' | '2024';
        /// The version of the crate. Used for calculating
        /// the correct docs.rs URL.
        version?: string;
        /// Dependencies
        deps: Dep[];
        /// Should this crate be treated as a member of
        /// current "workspace".
        ///
        /// By default, inferred from the `root_module`
        /// (members are the crates which reside inside
        /// the directory opened in the editor).
        ///
        /// Set this to `false` for things like standard
        /// library and 3rd party crates to enable
        /// performance optimizations (rust-analyzer
        /// assumes that non-member crates don't change).
        is_workspace_member?: boolean;
        /// Optionally specify the (super)set of `.rs`
        /// files comprising this crate.
        ///
        /// By default, rust-analyzer assumes that only
        /// files under `root_module.parent` can belong
        /// to a crate. `include_dirs` are included
        /// recursively, unless a subdirectory is in
        /// `exclude_dirs`.
        ///
        /// Different crates can share the same `source`.
        ///
        /// If two crates share an `.rs` file in common,
        /// they *must* have the same `source`.
        /// rust-analyzer assumes that files from one
        /// source can't refer to files in another source.
        source?: {
            include_dirs: string[];
            exclude_dirs: string[];
        };
        /// List of cfg groups this crate inherits.
        ///
        /// All cfg in these groups will be concatenated to
        /// `cfg`. It is impossible to replace a value from
        /// the groups.
        cfg_groups?: string[];
        /// The set of cfgs activated for a given crate, like
        /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`.
        cfg: string[];
        /// Target tuple for this Crate.
        ///
        /// Used when running `rustc --print cfg`
        /// to get target-specific cfgs.
        target?: string;
        /// Environment variables, used for
        /// the `env!` macro
        env: { [key: string]: string; };

        /// Whether the crate is a proc-macro crate.
        is_proc_macro: boolean;
        /// For proc-macro crates, path to compiled
        /// proc-macro (.so file).
        proc_macro_dylib_path?: string;

        /// Repository, matching the URL that would be used
        /// in Cargo.toml.
        repository?: string;

        /// Build-specific data about this crate.
        build?: BuildInfo;
    }

    interface Dep {
        /// Index of a crate in the `crates` array.
        crate: number;
        /// Name as should appear in the (implicit)
        /// `extern crate name` declaration.
        name: string;
    }

    interface BuildInfo {
        /// The name associated with this crate.
        ///
        /// This is determined by the build system that produced
        /// the `rust-project.json` in question. For instance, if buck were used,
        /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
        ///
        /// Do not attempt to parse the contents of this string; it is a build system-specific
        /// identifier similar to `Crate::display_name`.
        label: string;
        /// Path corresponding to the build system-specific file defining the crate.
        build_file: string;
        /// The kind of target.
        ///
        /// This information is used to determine what sort
        /// of runnable codelens to provide, if any.
        target_kind: 'bin' | 'lib' | 'test';
    }

    interface Runnable {
        /// The program invoked by the runnable.
        ///
        /// For example, this might be `cargo`, `buck`, or `bazel`.
        program: string;
        /// The arguments passed to `program`.
        args: string[];
        /// The current working directory of the runnable.
        cwd: string;
        /// Used to decide what code lens to offer.
        ///
        /// `testOne`: This runnable will be used when the user clicks the 'Run Test'
        /// CodeLens above a test.
        ///
        /// The args for testOne can contain two template strings:
        /// `{label}` and `{test_id}`. `{label}` will be replaced
        /// with the `Build::label` and `{test_id}` will be replaced
        /// with the test name.
        kind: 'testOne' | string;
    }

This format is provisional and subject to change. Specifically, the `roots` setup will be different eventually.

There are three ways to feed `rust-project.json` to rust-analyzer:

- Place `rust-project.json` file at the root of the project, and rust-analyzer will discover it.

- Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request).

- Specify `"rust-analyzer.linkedProjects": [ { "roots": […​], "crates": […​] }]` inline.

Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`.

You can set the `RA_LOG` environment variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.

Note that calls to `cargo check` are disabled when using `rust-project.json` by default, so compilation errors and warnings will no longer be sent to your LSP client. To enable these compilation errors you will need to specify explicitly what command rust-analyzer should run to perform the checks using the `rust-analyzer.check.overrideCommand` configuration. As an example, the following configuration explicitly sets `cargo check` as the `check` command.

    { "rust-analyzer.check.overrideCommand": ["cargo", "check", "--message-format=json"] }

`check.overrideCommand` requires the command specified to output json error messages for rust-analyzer to consume. The `--message-format=json` flag does this for `cargo check` so whichever command you use must also output errors in this format. See the Configuration section for more information.