diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 4ea8dc8..b9122ab 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -22,16 +22,12 @@ jobs:
       matrix:
         os: [ubuntu-latest, windows-latest, macos-latest]
     steps:
-    - name: Install .NET
-      uses: actions/setup-dotnet@v3
-      with:
-        dotnet-version: |
-          6.0.x
-          8.0.x
     - name: Check out code
       uses: actions/checkout@v3
       with:
         fetch-depth: 0 # required to publish docs
+    - name: Install .NET
+      uses: actions/setup-dotnet@v4
     - name: Restore
       run: .\build.ps1 restore
     - name: Build
diff --git a/Directory.Build.props b/Directory.Build.props
index 0faaf43..ad5be64 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,8 +1,8 @@
 <Project>
 
   <PropertyGroup>
-    <VersionPrefix>3.0.0</VersionPrefix>
-    <PackageValidationBaselineVersion>2.8.0</PackageValidationBaselineVersion>
+    <VersionPrefix>3.1.0</VersionPrefix>
+    <PackageValidationBaselineVersion>3.0.0</PackageValidationBaselineVersion>
     <LangVersion>12.0</LangVersion>
     <Nullable>enable</Nullable>
     <ImplicitUsings>enable</ImplicitUsings>
diff --git a/Directory.Packages.props b/Directory.Packages.props
index ae712e5..6c07034 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,8 +3,8 @@
     <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
   </PropertyGroup>
   <ItemGroup>
-    <PackageVersion Include="Facility.CodeGen.Console" Version="2.14.0" />
-    <PackageVersion Include="Facility.Definition" Version="2.14.0" />
+    <PackageVersion Include="Facility.CodeGen.Console" Version="2.15.0" />
+    <PackageVersion Include="Facility.Definition" Version="2.15.0" />
     <PackageVersion Include="FluentAssertions" Version="6.12.0" />
     <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
     <PackageVersion Include="NUnit" Version="4.1.0" />
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 75597e3..fbd047a 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -2,6 +2,11 @@
 
 These are the NuGet package releases. See also [npm Release Notes](ReleaseNotesNpm.md).
 
+## 3.1.0
+
+* Drop support for end-of-life frameworks.
+* Use roll forward with .NET tool.
+
 ## 3.0.0
 
 * Support required fields as not optional in TypeScript.
diff --git a/dotnet-tools.json b/dotnet-tools.json
index 194ceef..628a8d8 100644
--- a/dotnet-tools.json
+++ b/dotnet-tools.json
@@ -3,7 +3,7 @@
   "isRoot": true,
   "tools": {
     "facilityconformance": {
-      "version": "2.29.0",
+      "version": "2.30.0",
       "commands": [
         "FacilityConformance"
       ],
diff --git a/src/Facility.CodeGen.JavaScript/Facility.CodeGen.JavaScript.csproj b/src/Facility.CodeGen.JavaScript/Facility.CodeGen.JavaScript.csproj
index d33a1e2..d6643a8 100644
--- a/src/Facility.CodeGen.JavaScript/Facility.CodeGen.JavaScript.csproj
+++ b/src/Facility.CodeGen.JavaScript/Facility.CodeGen.JavaScript.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netstandard2.0;net6.0;net7.0;net8.0</TargetFrameworks>
+    <TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
     <Description>A library that generates JavaScript or TypeScript for a Facility Service Definition.</Description>
     <PackageTags>Facility FSD JavaScript TypeScript CodeGen</PackageTags>
     <IsPackable>true</IsPackable>
diff --git a/src/Facility.CodeGen.JavaScript/JavaScriptGenerator.cs b/src/Facility.CodeGen.JavaScript/JavaScriptGenerator.cs
index ca64b75..661ef7c 100644
--- a/src/Facility.CodeGen.JavaScript/JavaScriptGenerator.cs
+++ b/src/Facility.CodeGen.JavaScript/JavaScriptGenerator.cs
@@ -218,7 +218,7 @@ public override CodeGenOutput GenerateOutput(ServiceInfo service)
 						{
 							var hasPathFields = httpMethodInfo.PathFields.Count != 0;
 							var jsUriDelim = hasPathFields ? "`" : "'";
-#if NET6_0_OR_GREATER
+#if !NETSTANDARD2_0
 							var jsUri = string.Concat(jsUriDelim, httpMethodInfo.Path.AsSpan(1), jsUriDelim);
 #else
 							var jsUri = jsUriDelim + httpMethodInfo.Path.Substring(1) + jsUriDelim;
@@ -1245,7 +1245,7 @@ private static bool FieldUsesKind(ServiceInfo service, ServiceFieldInfo field, S
 			return false;
 		}
 
-#if NET6_0_OR_GREATER
+#if !NETSTANDARD2_0
 		private static string ReplaceOrdinal(string value, string oldValue, string newValue) => value.Replace(oldValue, newValue, StringComparison.Ordinal);
 #else
 		private static string ReplaceOrdinal(string value, string oldValue, string newValue) => value.Replace(oldValue, newValue);
diff --git a/src/fsdgenjs/fsdgenjs.csproj b/src/fsdgenjs/fsdgenjs.csproj
index 8242284..47e5eb5 100644
--- a/src/fsdgenjs/fsdgenjs.csproj
+++ b/src/fsdgenjs/fsdgenjs.csproj
@@ -2,11 +2,12 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
+    <TargetFramework>net8.0</TargetFramework>
     <Description>A tool that generates JavaScript or TypeScript for a Facility Service Definition.</Description>
     <PackageTags>Facility FSD JavaScript TypeScript CodeGen</PackageTags>
     <IsPackable>true</IsPackable>
     <PackAsTool>true</PackAsTool>
+    <RollForward>Major</RollForward>
     <PackageReadmeFile>README.md</PackageReadmeFile>
   </PropertyGroup>
 
diff --git a/tools/Build/Build.cs b/tools/Build/Build.cs
index 3e29038..d1f6c6f 100644
--- a/tools/Build/Build.cs
+++ b/tools/Build/Build.cs
@@ -54,7 +54,7 @@ void CodeGen(bool verify)
 		RunCodeGen("conformance/ConformanceApi.fsd", "conformance/src/fastify/", "--fastify", "--indent", "2", "--disable-eslint", "--module", "jsConformanceApi");
 
 		void RunCodeGen(params string?[] args) =>
-			RunDotNet(new[] { "run", "--no-build", "--project", $"src/{codegen}", "-f", "net6.0", "-c", configuration, "--", "--newline", "lf", verifyOption }.Concat(args));
+			RunDotNet(new[] { "run", "--no-build", "--project", $"src/{codegen}", "-c", configuration, "--", "--newline", "lf", verifyOption }.Concat(args));
 	}
 
 	build.Target("build-npm")