daveconway.net

Devlog #3: Multiple Godot projects in one .NET solution

This is less of a game update and more of a "here's how to do a specific thing in Godot" post. Hopefully it's useful for someone out there some day, or a goddamn LLM will scrape it up and spit it out at some point.

I'm using Godot 4.7 and Visual Studio 2026 on Windows, but this is likely applicable to other versions and IDEs. I'll use Windows-style paths here. If you're on Linux, I assume you're already well-versed in constructing Linux paths.

(There's a tl;dr at the bottom, if you're well-versed in all this stuff already.)

The scenario

  1. I made a Godot project for my game, whose working title is Vesper's Nexus.
  2. I went to Project -> Project Settings -> General tab -> Scrolled way down on the left to Dotnet: Project -> set Assembly Name to VNexus.
  3. I went to Project -> Tools -> C# -> Create C# Solution.
  4. This created VNexus.sln and VNexus.csproj in my project directory.
  5. I thought, "I would like more projects in my solution, and I want one of them to be another Godot project. I don't want the secondary Godot project to be an actual game, though. I just want it to run some scripts that use Godot features."

If this sounds like you, good news! It's highly doable, if slightly annoying.

Fix up your solution directory

First, separate your project from your solution, because, by default, Godot just puts everything at the root solution level. If you don't have some of the files I mention here, don't worry; you may not be using ReSharper or git and that's fine.

  1. Close your solution in Visual Studio and your project in Godot, if you have either open.
  2. Go to your solution folder (e.g., C:\GameDev\VN).
  3. Create a new folder that's the same name as your main C# project (e.g., I have VNexus.csproj, so I created the folder VNexus).
  4. Move the following into the new folder: your .csproj and .csproj.user; project.godot; the hidden .godot folder; and any code/resource/assets/etc. files/folders you have (your game, basically), including icon.svg and icon.svg.import, if you kept them.
  5. This should leave your root solution folder with just your .sln and .sln.DotSettings.user, .editorconfig, and all your git stuff.

Next, open your .sln file in a text editor, and look for a line like:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VNexus", "VNexus.csproj", "{7582FA97-E3FE-441A-BF25-1A6F29942AF6}"

Just update it to reference the new directory for your project:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VNexus", "VNexus\VNexus.csproj", "{7582FA97-E3FE-441A-BF25-1A6F29942AF6}"

Save, then open your solution in your IDE and try to build it. Should be fine. Then open Godot -- it won't be able to find your game in the recent projects list, but that's okay. Just remove that entry, click Import at the top, and navigate to the new directory you made and dropped your project.godot into. You should be able to run your game fine.

If you have a problem with either of those, try clearing the respective caches: delete the hidden .vs folder (or your IDE's equivalent) in your solution root, and delete the hidden .godot folder in your new project folder.

At this point you can add new assemblies to your solution as you would with any other C# solution -- test projects, class libraries, etc. I made a VNexus.Shared class library, for example, to hold resource classes that both my main game project and my secondary script-running Godot project need to reference.

Note: if you make any class libraries, I'd recommend making sure they target the same .NET version as your Godot project, obviously, but I'd also recommend turning off nullable reference type checking. There is a reason that Godot projects keep this off by default, and it's because so many of your objects' properties/members are made to be configured via the inspector, so you'd either be using [Export] private string _someString = null!; everywhere, or you'd be using [Export] private string? _someString; and then _someString! everywhere. This is because you're likely doing your validation in _Ready() (or you're just trusting properties to be set properly), and the compiler can't know that.

Creating a second Godot project

My ultimate goal here was running a second Godot project "headlessly" -- that is, without it needing to render anything. Make sure you actually need this! If you just need access to Godot types (e.g., Node, Resource, etc.), but you don't need access to the Godot runtime (i.e., you need to load a scene, create and save resources, etc.), you can get away with a class library. The VNexus.Shared class library that I mentioned just above provides no functionality on its own, so it doesn't need access to the Godot runtime, for example.

But for my VNexus.ResourceBuilder project, I need to use built-in Godot functionality, namely ResourceSaver.Save(), which can only execute via the Godot runtime. So I needed it to be a true Godot project. Fortunately, Godot has built-in support for running headlessly, so 

For me, the easiest way to achieve this was to create a new project via the Godot UI in a location totally separate to my existing project. So go back up to the start of the article, follow the first few steps again, then do a couple extra things:

  1. Create a new Godot project (mine was "Vesper's Nexus Resource Builder") in a totally separate directory, e.g.: C:\GameDev\Temp. Under "Version Control Metadata," just choose "None," since you'll be using the git or whatever from your main project.
  2. Set Assembly Name to whatever you want it to be in your real solution, e.g.: VNexus.ResourceBuilder.
  3. Have Godot build the C# solution, which will create new .sln and .csproj files.
  4. Create a new scene that extends Node. I named mine ResourceBuilderRunner.
  5. Attach a new C# script to it.
  6. Go to Project -> Project Settings -> General tab -> Application: Run on the left at the top -> set Main Scene to your new scene.

Moving it to your Main Solution

Super easy:

  1. In your main solution directory, add a new directory for the project that matches the name of the .csproj you just generated (e.g., VNexus.ResourceBuilder).
  2. Copy everything in the new Godot project's directory over to the new project directory.
  3. Delete the .sln and .editorconfig files.
  4. Open your solution in Visual Studio, right-click on the solution itself in the explorer, and go to Add -> Existing Project...
  5. Find the .csproj you just copied over and add it.

Running it from the command line

I'd recommend adding the directory with your Godot .NET executable to your PATH:

  1. Hit the windows key and type "environment."
  2. Click Edit the system environment variables.
  3. Click Environment Variables...
  4. Select the one called "Path" and click Edit...
  5. Click New.
  6. Paste in the directory that has your Godot .NET executable in it (e.g., C:\GameDev\Godot .NET).

Now go to that directory and create a new file named godot.bat (or whatever you want, but the name sans extension will be the command you run from the command line), and give it the following contents:

@echo off
"Godot_v4.7.1-stable_mono_win64_console.exe" %*

The first line is optional and makes it less verbose when you run it. The second line executes the console version of Godot, and the %* just passes along any arguments you specify.

If that's all working, you should be able to do something like this in PowerShell, and get an answer back:

PS C:\Users\Dave> godot --version
4.7.1.stable.mono.official.a13da4feb

Now you can try running your secondary project headlessly! Open the C# file attached to your primary scene and give it a _Ready() function that prints something out then exits the process. Here's mine, for example:

using Godot;

namespace VNexus.ResourceBuilder;

/// <summary>
/// Runs the YAML to .tres converter.
/// </summary>
public partial class ResourceBuilderRunner : Node
{
    /// <inheritdoc />
    public override void _Ready()
    {
        GD.Print("Running headlessly!");
        GetTree().Quit();
    }
}

If you open a Developer PowerShell in Visual Studio, you can try to run the project headlessly like this:

PS C:\GameDev\VN> godot --path .\VNexus.ResourceBuilder --headless
Godot Engine v4.7.1.stable.mono.official.a13da4feb - https://godotengine.org

Running headlessly!
PS C:\GameDev\VN>

Obviously, use your project directory.

Running it automatically as part of your build process

There are a couple ways you can do this, but I opted to do it as part of a new build configuration, so I'll explain that. You can look up other ways online.

Do the following in Visual Studio:

  1. Go to Build -> Configuration Manager...
  2. Under Active solution configuration:, select <New...>.
  3. In the pop-up, enter your build name. I wanted something that mimicked Debug but just ran my resource builder, so I called it, brilliantly, "DebugAndBuildResources" and had it copy settings from Debug. Keep Create new project configurations checked.
  4. Click Ok and then Close.

What you do next depends more on how you want your build process to work, but because I don't care whether my main project builds, I added the post-build command directly to the .csproj of the Godot project that I want to run headlessly. You may not want yours to run unless the entire solution builds, in which case I'd put it on my main Godot project. But here's what I added (at the level right below the root <Project> tag):

  <Target Name="RunResourceBuilder" AfterTargets="Build" Condition="'$(Configuration)' == 'DebugAndBuildResources'">
    <Exec Command="powershell.exe -Command &quot;&amp; godot --path '$(MSBuildProjectDirectory)' --headless&quot;" />
  </Target>

One nice thing about this is that it only fires when I'm using the new build configuration, so if I haven't changed any of my data files, I can skip the added build time and just use my normal debug build.

One annoying thing about this is that if I've only changed data files, but not the code, I must be sure to rebuild, and not just build, the project to get it to run again. But that's a minor annoyance.

And that's "it"! Happy coding!

tl;dr

If you're fluent in all this stuff and don't want to read all this text, here's the condensed version:

  • Move your Godot C# project into a subdirectory of the C# solution.
  • Create a second Godot project, generate a C# solution and project for it.
  • Create and add a main scene and a script for that scene that runs whatever code you want in _Ready() then exits Godot.
  • Copy that all over to your main C# solution, delete the unneeded solution file.
  • Either run it from the command line using the --headless option, or add an auto-run command into your project build config.