diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts
index b161473d9a..436529ca67 100644
--- a/packages/backend-rs/index.d.ts
+++ b/packages/backend-rs/index.d.ts
@@ -1292,6 +1292,7 @@ export interface AbuseUserReportLike {
   comment: string
 }
 export function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): void
+export function publishToNotesStream(note: Note): void
 export function getTimestamp(id: string): number
 /**
  * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`.
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index 0d9938f9ed..96f14541d1 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -310,7 +310,7 @@ if (!nativeBinding) {
   throw new Error(`Failed to load native binding`)
 }
 
-const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding
+const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, publishToNotesStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding
 
 module.exports.SECOND = SECOND
 module.exports.MINUTE = MINUTE
@@ -381,6 +381,7 @@ module.exports.publishToChatIndexStream = publishToChatIndexStream
 module.exports.publishToBroadcastStream = publishToBroadcastStream
 module.exports.publishToGroupChatStream = publishToGroupChatStream
 module.exports.publishToModerationStream = publishToModerationStream
+module.exports.publishToNotesStream = publishToNotesStream
 module.exports.getTimestamp = getTimestamp
 module.exports.genId = genId
 module.exports.genIdAt = genIdAt
diff --git a/packages/backend-rs/src/service/stream.rs b/packages/backend-rs/src/service/stream.rs
index 279d343f10..bf957a6e9b 100644
--- a/packages/backend-rs/src/service/stream.rs
+++ b/packages/backend-rs/src/service/stream.rs
@@ -5,6 +5,7 @@ pub mod chat_index;
 pub mod custom_emoji;
 pub mod group_chat;
 pub mod moderation;
+pub mod new_note;
 
 use crate::config::CONFIG;
 use crate::database::redis_conn;
@@ -25,7 +26,7 @@ pub enum Stream {
     #[strum(to_string = "noteStream:{note_id}")]
     Note { note_id: String },
     #[strum(serialize = "notesStream")]
-    Notes,
+    NewNote,
     #[strum(to_string = "userListStream:{list_id}")]
     UserList { list_id: String },
     #[strum(to_string = "mainStream:{user_id}")]
diff --git a/packages/backend-rs/src/service/stream/new_note.rs b/packages/backend-rs/src/service/stream/new_note.rs
new file mode 100644
index 0000000000..5386252ff7
--- /dev/null
+++ b/packages/backend-rs/src/service/stream/new_note.rs
@@ -0,0 +1,10 @@
+use crate::model::entity::note;
+use crate::service::stream::{publish_to_stream, Error, Stream};
+
+// for napi export (https://github.com/napi-rs/napi-rs/issues/2060)
+type Note = note::Model;
+
+#[crate::export(js_name = "publishToNotesStream")]
+pub fn publish(note: &Note) -> Result<(), Error> {
+    publish_to_stream(&Stream::NewNote, None, Some(serde_json::to_string(note)?))
+}
diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts
index 2096f8b1a2..95670b06b5 100644
--- a/packages/backend/src/services/note/create.ts
+++ b/packages/backend/src/services/note/create.ts
@@ -1,9 +1,5 @@
 import * as mfm from "mfm-js";
-import {
-	publishMainStream,
-	publishNotesStream,
-	publishNoteStream,
-} from "@/services/stream.js";
+import { publishMainStream, publishNoteStream } from "@/services/stream.js";
 import DeliverManager from "@/remote/activitypub/deliver-manager.js";
 import renderNote from "@/remote/activitypub/renderer/note.js";
 import renderCreate from "@/remote/activitypub/renderer/create.js";
@@ -49,6 +45,7 @@ import {
 	genId,
 	genIdAt,
 	isSilencedServer,
+	publishToNotesStream,
 } from "backend-rs";
 import { countSameRenotes } from "@/misc/count-same-renotes.js";
 import { deliverToRelays, getCachedRelays } from "../relay.js";
@@ -511,7 +508,7 @@ export default async (
 								30,
 							);
 						}
-						publishNotesStream(noteToPublish);
+						publishToNotesStream(toRustObject(noteToPublish));
 					}
 				} finally {
 					await lock.release();
diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts
index 36914d4d41..c60d5ce974 100644
--- a/packages/backend/src/services/stream.ts
+++ b/packages/backend/src/services/stream.ts
@@ -193,9 +193,10 @@ class Publisher {
 	// 	);
 	// };
 
-	public publishNotesStream = (note: Note): void => {
-		this.publish("notesStream", null, note);
-	};
+	/* ported to backend-rs */
+	// public publishNotesStream = (note: Note): void => {
+	// 	this.publish("notesStream", null, note);
+	// };
 
 	/* ported to backend-rs */
 	// public publishAdminStream = <K extends keyof AdminStreamTypes>(
@@ -221,7 +222,7 @@ export const publishUserEvent = publisher.publishUserEvent;
 export const publishMainStream = publisher.publishMainStream;
 export const publishDriveStream = publisher.publishDriveStream;
 export const publishNoteStream = publisher.publishNoteStream;
-export const publishNotesStream = publisher.publishNotesStream;
+// export const publishNotesStream = publisher.publishNotesStream;
 // export const publishChannelStream = publisher.publishChannelStream;
 export const publishUserListStream = publisher.publishUserListStream;
 // export const publishAntennaStream = publisher.publishAntennaStream;