diff --git a/lib/manager/npm/post-update/types.ts b/lib/manager/npm/post-update/types.ts
index 035ac3d39d47c23597a4f0f664d2c4a5f8deacef..2b780ddc89ee9df84e4477be0a486f8a03cfda21 100644
--- a/lib/manager/npm/post-update/types.ts
+++ b/lib/manager/npm/post-update/types.ts
@@ -19,6 +19,7 @@ export interface ArtifactError {
 export interface UpdatedArtifacts {
   name: string;
   contents: string | Buffer;
+  mode?: string | number;
 }
 
 export interface WriteExistingFilesResult {
diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts
index d7412b372082832a59a5b28670bf2a0f0f4f94fb..a3e6d78857ba72e7e4dfef1ce45fd9ba2e2e5561 100644
--- a/lib/util/git/index.spec.ts
+++ b/lib/util/git/index.spec.ts
@@ -412,6 +412,23 @@ describe('util/git/index', () => {
         expect.objectContaining({ '--no-verify': null })
       );
     });
+
+    it('creates file with specified mode', async () => {
+      const file = {
+        name: 'some-executable',
+        contents: 'some new-contents',
+        mode: 0o755,
+      };
+      const commit = await git.commitFiles({
+        branchName: 'renovate/past_branch',
+        files: [file],
+        message: 'Create something',
+      });
+      const { mode } = await fs.stat(tmpDir.path + '/some-executable');
+      expect(commit).not.toBeNull();
+      // eslint-disable-next-line no-bitwise
+      expect(mode & 0o777).toBe(0o755);
+    });
   });
 
   describe('getCommitMessages()', () => {
diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 3c7610ecb4562b349aaf34c411abbddd3dcc74c3..fa5998ada00ce0ae8ec1226364fda0e0eeffcd3e 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -653,6 +653,11 @@ export interface File {
    * file contents
    */
   contents: string | Buffer;
+
+  /**
+   * file mode
+   */
+  mode?: fs.Mode;
 }
 
 export type CommitFilesConfig = {
@@ -698,7 +703,8 @@ export async function commitFiles({
           ignoredFiles.push(fileName);
         }
       } else {
-        if (await isDirectory(join(localDir, fileName))) {
+        const path = join(localDir, fileName);
+        if (await isDirectory(path)) {
           // This is usually a git submodule update
           logger.trace({ fileName }, 'Adding directory commit');
         } else {
@@ -709,7 +715,10 @@ export async function commitFiles({
           } else {
             contents = file.contents;
           }
-          await fs.outputFile(join(localDir, fileName), contents);
+          await fs.outputFile(path, contents);
+          if (file.mode) {
+            await fs.chmod(path, file.mode);
+          }
         }
         try {
           await git.add(fileName);