diff --git a/src/client/app/boot.js b/src/client/app/boot.js
index da1b64823f..7b884c8a54 100644
--- a/src/client/app/boot.js
+++ b/src/client/app/boot.js
@@ -18,6 +18,14 @@
 		return;
 	}
 
+	//#region Load settings
+	let settings = null;
+	const vuex = localStorage.getItem('vuex');
+	if (vuex) {
+		settings = JSON.parse(vuex);
+	}
+	//#endregion
+
 	// Get the current url information
 	const url = new URL(location.href);
 
@@ -35,10 +43,8 @@
 	// The default language is English
 	if (!LANGS.includes(lang)) lang = 'en';
 
-	const vuex = localStorage.getItem('vuex');
-	if (vuex) {
-		const data = JSON.parse(vuex);
-		if (data.device.lang) lang = data.device.lang;
+	if (settings) {
+		if (settings.device.lang) lang = settings.device.lang;
 	}
 	//#endregion
 
@@ -68,8 +74,10 @@
 	}
 
 	// Dark/Light
-	if (localStorage.getItem('darkmode') == 'true') {
-		document.documentElement.setAttribute('data-darkmode', 'true');
+	if (settings) {
+		if (settings.device.darkmode) {
+			document.documentElement.setAttribute('data-darkmode', 'true');
+		}
 	}
 
 	// Script version
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 3fe09b9acc..dac5fe67cb 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -227,8 +227,7 @@ export default Vue.extend({
 			version,
 			langs,
 			latestVersion: undefined,
-			checkingForUpdate: false,
-			darkmode: localStorage.getItem('darkmode') == 'true'
+			checkingForUpdate: false
 		};
 	},
 	computed: {
@@ -246,6 +245,11 @@ export default Vue.extend({
 			set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); }
 		},
 
+		darkmode: {
+			get() { return this.$store.state.device.darkmode; },
+			set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
+		},
+
 		enableSounds: {
 			get() { return this.$store.state.device.enableSounds; },
 			set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
@@ -276,11 +280,6 @@ export default Vue.extend({
 			set(value) { this.$store.commit('device/set', { key: 'enableExperimentalFeatures', value }); }
 		}
 	},
-	watch: {
-		darkmode() {
-			(this as any)._updateDarkmode_(this.darkmode);
-		}
-	},
 	created() {
 		(this as any).os.getMeta().then(meta => {
 			this.meta = meta;
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index fd15ea6006..f3f6539496 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -35,7 +35,7 @@
 			</ul>
 			<ul>
 				<li @click="dark">
-					<p><span>%i18n:@dark%</span><template v-if="_darkmode_">%fa:moon%</template><template v-else>%fa:R moon%</template></p>
+					<p><span>%i18n:@dark%</span><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></p>
 				</li>
 			</ul>
 		</div>
@@ -99,7 +99,10 @@ export default Vue.extend({
 			(this as any).os.signout();
 		},
 		dark() {
-			(this as any)._updateDarkmode_(!(this as any)._darkmode_);
+			this.$store.commit('device/set', {
+				key: 'darkmode',
+				value: !this.$store.state.device.darkmode
+			});
 		}
 	}
 });
diff --git a/src/client/app/desktop/views/components/user-lists-window.vue b/src/client/app/desktop/views/components/user-lists-window.vue
index 585c0a864f..454c725d20 100644
--- a/src/client/app/desktop/views/components/user-lists-window.vue
+++ b/src/client/app/desktop/views/components/user-lists-window.vue
@@ -2,7 +2,7 @@
 <mk-window ref="window" is-modal width="450px" height="500px" @closed="$destroy">
 	<span slot="header">%fa:list% リスト</span>
 
-	<div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="_darkmode_">
+	<div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="$store.state.device.darkmode">
 		<button class="ui" @click="add">%i18n:@create-list%</button>
 		<a v-for="list in lists" :key="list.id" @click="choice(list)">{{ list.title }}</a>
 	</div>
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index afa0a4810b..83c668a9cf 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mk-welcome">
 	<button @click="dark">
-		<template v-if="_darkmode_">%fa:moon%</template>
+		<template v-if="$store.state.device.darkmode">%fa:moon%</template>
 		<template v-else>%fa:R moon%</template>
 	</button>
 	<main>
-		<img :src="_darkmode_ ? 'assets/title-dark.svg' : 'assets/title.svg'" alt="Misskey">
+		<img :src="$store.state.device.darkmode ? 'assets/title-dark.svg' : 'assets/title.svg'" alt="Misskey">
 		<p><button class="signup" @click="signup">%i18n:@signup-button%</button><button class="signin" @click="signin">%i18n:@signin-button%</button></p>
 
 		<div class="tl">
@@ -50,7 +50,6 @@ export default Vue.extend({
 			this.$modal.show('signin');
 		},
 		dark() {
-			(this as any)._updateDarkmode_(!(this as any)._darkmode_);
 		}
 	}
 });
diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue
index 36fcc20636..7421a81102 100644
--- a/src/client/app/desktop/views/widgets/polls.vue
+++ b/src/client/app/desktop/views/widgets/polls.vue
@@ -4,7 +4,7 @@
 		<template slot="header">%fa:chart-pie%%i18n:@title%</template>
 		<button slot="func" title="%i18n:@refresh%" @click="fetch">%fa:sync%</button>
 
-		<div class="mkw-polls--body" :data-darkmode="_darkmode_">
+		<div class="mkw-polls--body" :data-darkmode="$store.state.device.darkmode">
 			<div class="poll" v-if="!fetching && poll != null">
 				<p v-if="poll.text"><router-link to="poll | notePage">{{ poll.text }}</router-link></p>
 				<p v-if="!poll.text"><router-link to="poll | notePage">%fa:link%</router-link></p>
diff --git a/src/client/app/init.ts b/src/client/app/init.ts
index 34bc6a2785..d764beb3bd 100644
--- a/src/client/app/init.ts
+++ b/src/client/app/init.ts
@@ -49,48 +49,6 @@ Vue.mixin({
 	}
 });
 
-// Dark/Light
-const bus = new Vue();
-Vue.mixin({
-	data() {
-		return {
-			_darkmode_: localStorage.getItem('darkmode') == 'true'
-		};
-	},
-	beforeCreate() {
-		// なぜか警告が出るので
-		this._darkmode_ = localStorage.getItem('darkmode') == 'true';
-	},
-	beforeDestroy() {
-		bus.$off('updated', this._onDarkmodeUpdated_);
-	},
-	mounted() {
-		this._onDarkmodeUpdated_(this._darkmode_);
-		bus.$on('updated', this._onDarkmodeUpdated_);
-	},
-	methods: {
-		_updateDarkmode_(v) {
-			localStorage.setItem('darkmode', v.toString());
-			if (v) {
-				document.documentElement.setAttribute('data-darkmode', 'true');
-			} else {
-				document.documentElement.removeAttribute('data-darkmode');
-			}
-			bus.$emit('updated', v);
-		},
-		_onDarkmodeUpdated_(v) {
-			if (!this.$el || !this.$el.setAttribute) return;
-			if (v) {
-				this.$el.setAttribute('data-darkmode', 'true');
-			} else {
-				this.$el.removeAttribute('data-darkmode');
-			}
-			this._darkmode_ = v;
-			this.$forceUpdate();
-		}
-	}
-});
-
 /**
  * APP ENTRY POINT!
  */
@@ -141,6 +99,43 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
 		const launch = (router: VueRouter, api?: (os: MiOS) => API) => {
 			os.apis = api ? api(os) : null;
 
+			//#region Dark/Light
+			Vue.mixin({
+				data() {
+					_unwatchDarkmode_: null
+				},
+				created() {
+					const apply = v => {
+						if (this.$el.setAttribute == null) return;
+						if (v) {
+							this.$el.setAttribute('data-darkmode', 'true');
+						} else {
+							this.$el.removeAttribute('data-darkmode');
+						}
+					};
+
+					this.$nextTick(() => apply(os.store.state.device.darkmode));
+
+					this._unwatchDarkmode_ = os.store.watch(s => {
+						return s.device.darkmode;
+					}, apply);
+				},
+				beforeDestroy() {
+					this._unwatchDarkmode_();
+				}
+			});
+
+			os.store.watch(s => {
+				return s.device.darkmode;
+			}, v => {
+				if (v) {
+					document.documentElement.setAttribute('data-darkmode', 'true');
+				} else {
+					document.documentElement.removeAttribute('data-darkmode');
+				}
+			});
+			//#endregion
+
 			Vue.mixin({
 				data() {
 					return {
diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue
index 2e4a5cd22a..aa469bd1c8 100644
--- a/src/client/app/mobile/views/components/ui.nav.vue
+++ b/src/client/app/mobile/views/components/ui.nav.vue
@@ -29,7 +29,7 @@
 				</ul>
 				<ul>
 					<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
-					<li @click="dark"><p><template v-if="_darkmode_">%fa:moon%</template><template v-else>%fa:R moon%</template><span>ダークモード</span></p></li>
+					<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>ダークモード</span></p></li>
 				</ul>
 			</div>
 			<a :href="aboutUrl"><p class="about">%i18n:@about%</p></a>
@@ -117,7 +117,10 @@ export default Vue.extend({
 			this.hasGameInvitations = false;
 		},
 		dark() {
-			(this as any)._updateDarkmode_(!(this as any)._darkmode_);
+			this.$store.commit('device/set', {
+				key: 'darkmode',
+				value: !this.$store.state.device.darkmode
+			});
 		}
 	}
 });
diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue
index ad6d5ed408..4d10b7016a 100644
--- a/src/client/app/mobile/views/pages/home.vue
+++ b/src/client/app/mobile/views/pages/home.vue
@@ -17,7 +17,7 @@
 		<button @click="fn">%fa:pencil-alt%</button>
 	</template>
 
-	<main :data-darkmode="_darkmode_">
+	<main :data-darkmode="$store.state.device.darkmode">
 		<div class="nav" v-if="showNav">
 			<div class="bg" @click="showNav = false"></div>
 			<div class="body">
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 034e8525a0..270c9f4055 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -141,7 +141,6 @@ export default Vue.extend({
 			version,
 			codename,
 			langs,
-			darkmode: localStorage.getItem('darkmode') == 'true',
 			latestVersion: undefined,
 			checkingForUpdate: false
 		};
@@ -152,6 +151,11 @@ export default Vue.extend({
 			return Vue.filter('userName')((this as any).os.i);
 		},
 
+		darkmode: {
+			get() { return this.$store.state.device.darkmode; },
+			set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
+		},
+
 		postStyle: {
 			get() { return this.$store.state.device.postStyle; },
 			set(value) { this.$store.commit('device/set', { key: 'postStyle', value }); }
@@ -168,12 +172,6 @@ export default Vue.extend({
 		},
 	},
 
-	watch: {
-		darkmode() {
-			(this as any)._updateDarkmode_(this.darkmode);
-		}
-	},
-
 	mounted() {
 		document.title = 'Misskey | %i18n:@settings%';
 	},
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 34adeb03cd..84fd7eda02 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-ui>
 	<template slot="header" v-if="!fetching"><img :src="`${user.avatarUrl}?thumbnail&size=64`" alt="">{{ user | userName }}</template>
-	<main v-if="!fetching" :data-darkmode="_darkmode_">
+	<main v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
 		<div class="is-suspended" v-if="user.isSuspended"><p>%fa:exclamation-triangle% %i18n:@is-suspended%</p></div>
 		<div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></p></div>
 		<header>
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
index 972a994fb5..74a5852c1a 100644
--- a/src/client/app/store.ts
+++ b/src/client/app/store.ts
@@ -19,6 +19,7 @@ const defaultSettings = {
 const defaultDeviceSettings = {
 	apiViaStream: true,
 	autoPopout: false,
+	darkmode: false,
 	enableSounds: true,
 	soundVolume: 0.5,
 	lang: null,