diff --git a/package-lock.json b/package-lock.json
index 1656a45ef..2f9934868 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,7 @@
         "examples/statemachine"
       ],
       "devDependencies": {
-        "@types/node": "~16.18.41",
+        "@types/node": "^18.0.0",
         "@types/vscode": "~1.67.0",
         "@typescript-eslint/eslint-plugin": "~6.4.1",
         "@typescript-eslint/parser": "~6.4.1",
@@ -1764,9 +1764,13 @@
       "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="
     },
     "node_modules/@types/node": {
-      "version": "16.18.68",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.68.tgz",
-      "integrity": "sha512-sG3hPIQwJLoewrN7cr0dwEy+yF5nD4D/4FxtQpFciRD/xwUzgD+G05uxZHv5mhfXo4F9Jkp13jjn0CC2q325sg=="
+      "version": "18.19.70",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz",
+      "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
     },
     "node_modules/@types/normalize-package-data": {
       "version": "2.4.4",
@@ -9936,6 +9940,12 @@
       "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
       "dev": true
     },
+    "packages/generator-langium/node_modules/@types/node": {
+      "version": "16.18.123",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.123.tgz",
+      "integrity": "sha512-/n7I6V/4agSpJtFDKKFEa763Hc1z3hmvchobHS1TisCOTKD5nxq8NJ2iK7SRIMYL276Q9mgWOx2AWp5n2XI6eA==",
+      "license": "MIT"
+    },
     "packages/generator-langium/node_modules/@types/which": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.3.tgz",
diff --git a/package.json b/package.json
index 4c8ce7aa8..92e64be79 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
     "reset:repo": "git clean -f -X -d"
   },
   "devDependencies": {
-    "@types/node": "~16.18.41",
+    "@types/node": "^18.0.0",
     "@types/vscode": "~1.67.0",
     "@typescript-eslint/eslint-plugin": "~6.4.1",
     "@typescript-eslint/parser": "~6.4.1",
@@ -40,7 +40,7 @@
     "vitest": "~1.5.0"
   },
   "overrides": {
-    "@types/node": "~16.18.41"
+    "@types/node": "^18.0.0"
   },
   "volta": {
     "node": "18.19.1",
diff --git a/packages/langium/src/node/node-file-system-provider.ts b/packages/langium/src/node/node-file-system-provider.ts
index 740929a23..05d139b07 100644
--- a/packages/langium/src/node/node-file-system-provider.ts
+++ b/packages/langium/src/node/node-file-system-provider.ts
@@ -15,17 +15,51 @@ export class NodeFileSystemProvider implements FileSystemProvider {
 
     encoding: NodeTextEncoding = 'utf-8';
 
+    exists(uri: URI): Promise<boolean> {
+        return new Promise(resolve => {
+            fs.stat(uri.fsPath, err => {
+                resolve(!err);
+            });
+        });
+    }
+
+    existsSync(uri: URI): boolean {
+        return fs.existsSync(uri.fsPath);
+    }
+
+    readBinary(uri: URI): Promise<Uint8Array> {
+        return fs.promises.readFile(uri.fsPath);
+    }
+
+    readBinarySync(uri: URI): Uint8Array {
+        return fs.readFileSync(uri.fsPath);
+    }
+
     readFile(uri: URI): Promise<string> {
         return fs.promises.readFile(uri.fsPath, this.encoding);
     }
 
-    async readDirectory(folderPath: URI): Promise<FileSystemNode[]> {
-        const dirents = await fs.promises.readdir(folderPath.fsPath, { withFileTypes: true });
+    readFileSync(uri: URI): string {
+        return fs.readFileSync(uri.fsPath, this.encoding);
+    }
+
+    async readDirectory(uri: URI): Promise<FileSystemNode[]> {
+        const dirents = await fs.promises.readdir(uri.fsPath, { withFileTypes: true });
+        return dirents.map(dirent => ({
+            dirent, // Include the raw entry, it may be useful...
+            isFile: dirent.isFile(),
+            isDirectory: dirent.isDirectory(),
+            uri: UriUtils.joinPath(uri, dirent.name)
+        }));
+    }
+
+    readDirectorySync(uri: URI): FileSystemNode[] {
+        const dirents = fs.readdirSync(uri.fsPath, { withFileTypes: true });
         return dirents.map(dirent => ({
             dirent, // Include the raw entry, it may be useful...
             isFile: dirent.isFile(),
             isDirectory: dirent.isDirectory(),
-            uri: UriUtils.joinPath(folderPath, dirent.name)
+            uri: UriUtils.joinPath(uri, dirent.name)
         }));
     }
 }
diff --git a/packages/langium/src/workspace/file-system-provider.ts b/packages/langium/src/workspace/file-system-provider.ts
index 0c7a58d6c..70373ddaa 100644
--- a/packages/langium/src/workspace/file-system-provider.ts
+++ b/packages/langium/src/workspace/file-system-provider.ts
@@ -18,28 +18,82 @@ export type FileSystemFilter = (node: FileSystemNode) => boolean;
  * Provides methods to interact with an abstract file system. The default implementation is based on the node.js `fs` API.
  */
 export interface FileSystemProvider {
+    /**
+     * Checks if a file exists at the specified URI.
+     * @returns `true` if a file exists at the specified URI, `false` otherwise.
+     */
+    exists(uri: URI): Promise<boolean>;
+    /**
+     * Checks if a file exists at the specified URI synchronously.
+     * @returns `true` if a file exists at the specified URI, `false` otherwise.
+     */
+    existsSync(uri: URI): boolean;
+    /**
+     * Reads a binary file asynchronously from a given URI.
+     * @returns The binary content of the file with the specified URI.
+     */
+    readBinary(uri: URI): Promise<Uint8Array>;
+    /**
+     * Reads a binary file synchronously from a given URI.
+     * @returns The binary content of the file with the specified URI.
+     */
+    readBinarySync(uri: URI): Uint8Array;
     /**
      * Reads a document asynchronously from a given URI.
      * @returns The string content of the file with the specified URI.
      */
     readFile(uri: URI): Promise<string>;
+    /**
+     * Reads a document synchronously from a given URI.
+     * @returns The string content of the file with the specified
+     */
+    readFileSync(uri: URI): string;
     /**
      * Reads the directory information for the given URI.
      * @returns The list of file system entries that are contained within the specified directory.
      */
     readDirectory(uri: URI): Promise<FileSystemNode[]>;
+    /**
+     * Reads the directory information for the given URI synchronously.
+     * @returns The list of file system entries that are contained within the specified directory.
+     */
+    readDirectorySync(uri: URI): FileSystemNode[];
 }
 
 export class EmptyFileSystemProvider implements FileSystemProvider {
 
+    async exists(): Promise<boolean> {
+        return false;
+    }
+
+    existsSync(): boolean {
+        return false;
+    }
+
+    readBinary(): Promise<Uint8Array> {
+        throw new Error('No file system is available.');
+    }
+
+    readBinarySync(): Uint8Array {
+        throw new Error('No file system is available.');
+    }
+
     readFile(): Promise<string> {
         throw new Error('No file system is available.');
     }
 
+    readFileSync(): string {
+        throw new Error('No file system is available.');
+    }
+
     async readDirectory(): Promise<FileSystemNode[]> {
         return [];
     }
 
+    readDirectorySync(): FileSystemNode[] {
+        return [];
+    }
+
 }
 
 export const EmptyFileSystem = {