diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 29ceb8ebfd..3db383e378 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -239,6 +239,8 @@ drive: "ドライブ"
 fileName: "ファイル名"
 selectFile: "ファイルを選択"
 selectFiles: "ファイルを選択"
+selectFolder: "フォルダーを選択"
+selectFolders: "フォルダーを選択"
 renameFile: "ファイル名を変更"
 folderName: "フォルダー名"
 createFolder: "フォルダーを作成"
diff --git a/src/client/components/drive-window.vue b/src/client/components/drive-window.vue
index 64c4cee0c1..d63881c0ed 100644
--- a/src/client/components/drive-window.vue
+++ b/src/client/components/drive-window.vue
@@ -1,8 +1,11 @@
 <template>
-<x-window ref="window" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="selected.length === 0" @ok="ok()">
-	<template #header>{{ multiple ? $t('selectFiles') : $t('selectFile') }}<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ selected.length | number }})</span></template>
+<x-window ref="window" :width="800" :height="500" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="(type === 'file') && (selected.length === 0)" @ok="ok()">
+	<template #header>
+		{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
+		<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ selected.length | number }})</span>
+	</template>
 	<div>
-		<x-drive :multiple="multiple" @change-selection="onChangeSelection" :select-mode="true"/>
+		<x-drive :multiple="multiple" @change-selection="onChangeSelection" :select="type"/>
 	</div>
 </x-window>
 </template>
@@ -25,7 +28,7 @@ export default Vue.extend({
 		type: {
 			type: String,
 			required: false,
-			default: undefined 
+			default: 'file' 
 		},
 		multiple: {
 			type: Boolean,
@@ -45,8 +48,8 @@ export default Vue.extend({
 			this.$refs.window.close();
 		},
 
-		onChangeSelection(files) {
-			this.selected = files;
+		onChangeSelection(xs) {
+			this.selected = xs;
 		}
 	}
 });
diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue
index 014e1a6ca5..a547abf9a0 100644
--- a/src/client/components/drive.file.vue
+++ b/src/client/components/drive.file.vue
@@ -42,11 +42,20 @@ import { faDownload, faLink, faICursor, faTrashAlt } from '@fortawesome/free-sol
 export default Vue.extend({
 	i18n,
 
+	components: {
+		XFileThumbnail
+	},
+
 	props: {
 		file: {
 			type: Object,
 			required: true,
 		},
+		isSelected: {
+			type: Boolean,
+			required: false,
+			default: false,
+		},
 		selectMode: {
 			type: Boolean,
 			required: false,
@@ -54,10 +63,6 @@ export default Vue.extend({
 		}
 	},
 
-	components: {
-		XFileThumbnail
-	},
-
 	data() {
 		return {
 			isDragging: false
@@ -65,12 +70,10 @@ export default Vue.extend({
 	},
 
 	computed: {
+		// TODO: parentへの参照を無くす
 		browser(): any {
 			return this.$parent;
 		},
-		isSelected(): boolean {
-			return this.browser.selectedFiles.some(f => f.id == this.file.id);
-		},
 		title(): string {
 			return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.size)}`;
 		}
@@ -79,7 +82,7 @@ export default Vue.extend({
 	methods: {
 		onClick(ev) {
 			if (this.selectMode) {
-				this.browser.chooseFile(this.file);
+				this.$emit('chosen', this.file);
 			} else {
 				this.$root.menu({
 					items: [{
diff --git a/src/client/components/drive.folder.vue b/src/client/components/drive.folder.vue
index 2e861e2480..b778acc77f 100644
--- a/src/client/components/drive.folder.vue
+++ b/src/client/components/drive.folder.vue
@@ -21,6 +21,7 @@
 	<p class="upload" v-if="$store.state.settings.uploadFolder == folder.id">
 		{{ $t('uploadFolder') }}
 	</p>
+	<button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button>
 </div>
 </template>
 
@@ -36,6 +37,16 @@ export default Vue.extend({
 		folder: {
 			type: Object,
 			required: true,
+		},
+		isSelected: {
+			type: Boolean,
+			required: false,
+			default: false,
+		},
+		selectMode: {
+			type: Boolean,
+			required: false,
+			default: false,
 		}
 	},
 
@@ -56,7 +67,12 @@ export default Vue.extend({
 			return this.folder.name;
 		}
 	},
+
 	methods: {
+		checkboxClicked(e) {
+			this.$emit('chosen', this.folder);
+		},
+
 		onClick() {
 			this.browser.move(this.folder);
 		},
@@ -241,10 +257,24 @@ export default Vue.extend({
 		cursor: pointer;
 	}
 
-	* {
+	*:not(.checkbox) {
 		pointer-events: none;
 	}
 
+	> .checkbox {
+		position: absolute;
+		bottom: 8px;
+		right: 8px;
+		width: 16px;
+		height: 16px;
+		background: #fff;
+		border: solid 1px #000;
+
+		&.checked {
+			background: var(--accent);
+		}
+	}
+
 	&[data-draghover] {
 		&:after {
 			content: "";
diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue
index fddac5b9aa..08c7097a8f 100644
--- a/src/client/components/drive.vue
+++ b/src/client/components/drive.vue
@@ -3,9 +3,9 @@
 	<nav>
 		<div class="path" @contextmenu.prevent.stop="() => {}">
 			<x-nav-folder :class="{ current: folder == null }"/>
-			<template v-for="folder in hierarchyFolders">
-				<span class="separator"><fa :icon="faAngleRight"/></span>
-				<x-nav-folder :folder="folder" :key="folder.id"/>
+			<template v-for="f in hierarchyFolders">
+				<span class="separator" :key="f.id + ':separator'"><fa :icon="faAngleRight"/></span>
+				<x-nav-folder :folder="f" :key="f.id"/>
 			</template>
 			<span class="separator" v-if="folder != null"><fa :icon="faAngleRight"/></span>
 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
@@ -20,15 +20,15 @@
 	>
 		<div class="contents" ref="contents">
 			<div class="folders" ref="foldersContainer" v-if="folders.length > 0">
-				<x-folder v-for="folder in folders" :key="folder.id" class="folder" :folder="folder"/>
+				<x-folder v-for="f in folders" :key="f.id" class="folder" :folder="f" :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder"/>
 				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
-				<div class="padding" v-for="n in 16"></div>
+				<div class="padding" v-for="(n, i) in 16" :key="i"></div>
 				<mk-button v-if="moreFolders">{{ $t('loadMore') }}</mk-button>
 			</div>
 			<div class="files" ref="filesContainer" v-if="files.length > 0">
-				<x-file v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="selectMode"/>
+				<x-file v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === file.id)" @chosen="chooseFile"/>
 				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
-				<div class="padding" v-for="n in 16"></div>
+				<div class="padding" v-for="(n, i) in 16" :key="i"></div>
 				<mk-button v-if="moreFiles" @click="fetchMoreFiles">{{ $t('loadMore') }}</mk-button>
 			</div>
 			<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
@@ -81,10 +81,10 @@ export default Vue.extend({
 			required: false,
 			default: false
 		},
-		selectMode: {
-			type: Boolean,
+		select: {
+			type: String,
 			required: false,
-			default: false
+			default: null
 		}
 	},
 
@@ -102,6 +102,7 @@ export default Vue.extend({
 			moreFolders: false,
 			hierarchyFolders: [],
 			selectedFiles: [],
+			selectedFolders: [],
 			uploadings: [],
 			connection: null,
 
@@ -392,6 +393,25 @@ export default Vue.extend({
 			}
 		},
 
+		chooseFolder(folder) {
+			const isAlreadySelected = this.selectedFolders.some(f => f.id == folder.id);
+			if (this.multiple) {
+				if (isAlreadySelected) {
+					this.selectedFolders = this.selectedFolders.filter(f => f.id != folder.id);
+				} else {
+					this.selectedFolders.push(folder);
+				}
+				this.$emit('change-selection', this.selectedFolders);
+			} else {
+				if (isAlreadySelected) {
+					this.$emit('selected', folder);
+				} else {
+					this.selectedFolders = [folder];
+					this.$emit('change-selection', [folder]);
+				}
+			}
+		},
+
 		move(target) {
 			if (target == null) {
 				this.goRoot();
diff --git a/src/client/components/page/page.post.vue b/src/client/components/page/page.post.vue
index 9942a68d55..6f79374f34 100644
--- a/src/client/components/page/page.post.vue
+++ b/src/client/components/page/page.post.vue
@@ -58,6 +58,9 @@ export default Vue.extend({
 					const data = new FormData();
 					data.append('file', blob);
 					data.append('i', this.$store.state.i.token);
+					if (this.$store.state.settings.uploadFolder) {
+						data.append('folderId', this.$store.state.settings.uploadFolder);
+					}
 
 					fetch(apiUrl + '/drive/files/create', {
 						method: 'POST',
diff --git a/src/client/components/window.vue b/src/client/components/window.vue
index bfdabee059..0b2ba248bf 100644
--- a/src/client/components/window.vue
+++ b/src/client/components/window.vue
@@ -1,6 +1,6 @@
 <template>
 <x-modal ref="modal" @closed="() => { $emit('closed'); destroyDom(); }">
-	<div class="ebkgoccj" :class="{ noPadding }" @keydown="onKeydown">
+	<div class="ebkgoccj" :class="{ noPadding }" @keydown="onKeydown" :style="{ width: `${width}px`, height: `${height}px` }">
 		<div class="header">
 			<button class="_button" v-if="withOkButton" @click="close()"><fa :icon="faTimes"/></button>
 			<span class="title">
@@ -49,7 +49,17 @@ export default Vue.extend({
 			type: Boolean,
 			required: false,
 			default: false
-		}
+		},
+		width: {
+			type: Number,
+			required: false,
+			default: 400
+		},
+		height: {
+			type: Number,
+			required: false,
+			default: 400
+		},
 	},
 
 	data() {
@@ -76,19 +86,12 @@ export default Vue.extend({
 
 <style lang="scss" scoped>
 .ebkgoccj {
-	width: 400px;
-	height: 400px;
 	background: var(--panel);
 	border-radius: var(--radius);
 	overflow: hidden;
 	display: flex;
 	flex-direction: column;
 
-	@media (max-width: 500px) {
-		width: 350px;
-		height: 350px;
-	}
-
 	> .header {
 		$height: 58px;
 		$height-narrow: 42px;
diff --git a/src/client/pages/my-settings/drive.vue b/src/client/pages/my-settings/drive.vue
index 55372687fc..c3d2d1dc2d 100644
--- a/src/client/pages/my-settings/drive.vue
+++ b/src/client/pages/my-settings/drive.vue
@@ -2,107 +2,57 @@
 <section class="uawsfosz _card">
 	<div class="_title"><fa :icon="faCloud"/> {{ $t('drive') }}</div>
 	<div class="_content">
-		<mk-pagination :pagination="drivePagination" #default="{items}" class="drive" ref="drive">
-			<div class="file" v-for="(file, i) in items" :key="file.id" @click="selected = file" :class="{ selected: selected && (selected.id === file.id) }">
-				<x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
-				<div class="body">
-					<p class="name">
-						<span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span>
-						<span class="ext" v-if="file.name.lastIndexOf('.') != -1">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span>
-					</p>
-					<footer>
-						<span class="type"><x-file-type-icon :type="file.type" class="icon"/>{{ file.type }}</span>
-						<span class="separator"></span>
-						<span class="data-size">{{ file.size | bytes }}</span>
-						<span class="separator"></span>
-						<span class="created-at"><fa :icon="faClock"/><mk-time :time="file.createdAt"/></span>
-						<template v-if="file.isSensitive">
-							<span class="separator"></span>
-							<span class="nsfw"><fa :icon="faEyeSlash"/> {{ $t('nsfw') }}</span>
-						</template>
-					</footer>
-				</div>
-			</div>
-		</mk-pagination>
-	</div>
-	<div class="_footer">
-		<mk-button primary inline :disabled="selected == null" @click="download()"><fa :icon="faDownload"/> {{ $t('download') }}</mk-button>
-		<mk-button inline :disabled="selected == null" @click="del()"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</mk-button>
+		<span>{{ $t('uploadFolder') }}: {{ uploadFolder ? uploadFolder.name : '-' }}</span>
+		<mk-button primary @click="chooseUploadFolder()"><fa :icon="faFolderOpen"/> {{ $t('selectFolder') }}</mk-button>
 	</div>
 </section>
 </template>
 
 <script lang="ts">
 import Vue from 'vue';
-import { faCloud, faDownload } from '@fortawesome/free-solid-svg-icons';
+import { faCloud, faFolderOpen } from '@fortawesome/free-solid-svg-icons';
 import { faClock, faEyeSlash, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
-import XFileTypeIcon from '../../components/file-type-icon.vue';
-import XFileThumbnail from '../../components/drive-file-thumbnail.vue';
 import MkButton from '../../components/ui/button.vue';
-import MkPagination from '../../components/ui/pagination.vue';
 import i18n from '../../i18n';
+import { selectDriveFolder } from '../../scripts/select-drive-folder';
 
 export default Vue.extend({
 	i18n,
 
 	components: {
-		XFileTypeIcon,
-		XFileThumbnail,
-		MkPagination,
 		MkButton,
 	},
 
 	data() {
 		return {
-			selected: null,
-			connection: null,
-			drivePagination: {
-				endpoint: 'drive/files',
-				limit: 10,
-			},
-			faCloud, faClock, faEyeSlash, faDownload, faTrashAlt
+			uploadFolder: null,
+			faCloud, faClock, faEyeSlash, faFolderOpen, faTrashAlt
 		}
 	},
 
-	created() {
-		this.connection = this.$root.stream.useSharedConnection('drive');
-
-		this.connection.on('fileCreated', this.onStreamDriveFileCreated);
-		this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
-		this.connection.on('fileDeleted', this.onStreamDriveFileDeleted);
-	},
-
-	beforeDestroy() {
-		this.connection.dispose();
+	async created() {
+		if (this.$store.state.settings.uploadFolder) {
+			this.uploadFolder = await this.$root.api('drive/folders/show', {
+				folderId: this.$store.state.settings.uploadFolder
+			});
+		}
 	},
 
 	methods: {
-		onStreamDriveFileCreated(file) {
-			this.$refs.drive.prepend(file);
-		},
-
-		onStreamDriveFileUpdated(file) {
-			// TODO
-		},
-
-		onStreamDriveFileDeleted(fileId) {
-			this.$refs.drive.remove(x => x.id === fileId);
-		},
-
-		download() {
-			window.open(this.selected.url, '_blank');
-		},
-
-		async del() {
-			const { canceled } = await this.$root.dialog({
-				type: 'warning',
-				text: this.$t('driveFileDeleteConfirm', { name: this.selected.name }),
-				showCancelButton: true
-			});
-			if (canceled) return;
-
-			this.$root.api('drive/files/delete', {
-				fileId: this.selected.id
+		chooseUploadFolder() {
+			selectDriveFolder(this.$root, false).then(async folder => {
+				await this.$store.dispatch('settings/set', { key: 'uploadFolder', value: folder ? folder.id : null });
+				this.$root.dialog({
+					type: 'success',
+					iconOnly: true, autoClose: true
+				});
+				if (this.$store.state.settings.uploadFolder) {
+					this.uploadFolder = await this.$root.api('drive/folders/show', {
+						folderId: this.$store.state.settings.uploadFolder
+					});
+				} else {
+					this.uploadFolder = null;
+				}
 			});
 		}
 	}
@@ -111,102 +61,6 @@ export default Vue.extend({
 
 <style lang="scss" scoped>
 .uawsfosz {
-	> ._content {
-		max-height: 350px;
-		overflow: auto;
-		
-		> .drive {
-			> .file {
-				display: grid;
-				margin: 0 auto;
-				grid-template-columns: 64px 1fr;
-				grid-column-gap: 10px;
-				cursor: pointer;
 
-				&.selected {
-					background: var(--accent);
-					box-shadow: 0 0 0 8px var(--accent);
-					color: #fff;
-				}
-
-				&:not(:last-child) {
-					margin-bottom: 16px;
-				}
-
-				> .thumbnail {
-					width: 64px;
-					height: 64px;
-				}
-
-				> .body {
-					display: block;
-					word-break: break-all;
-					padding-top: 4px;
-
-					> .name {
-						display: block;
-						margin: 0;
-						padding: 0;
-						font-size: 0.9em;
-						font-weight: bold;
-						word-break: break-word;
-
-						> .ext {
-							opacity: 0.5;
-						}
-					}
-
-					> .tags {
-						display: block;
-						margin: 4px 0 0 0;
-						padding: 0;
-						list-style: none;
-						font-size: 0.5em;
-
-						> .tag {
-							display: inline-block;
-							margin: 0 5px 0 0;
-							padding: 1px 5px;
-							border-radius: 2px;
-						}
-					}
-
-					> footer {
-						display: block;
-						margin: 4px 0 0 0;
-						font-size: 0.7em;
-
-						> .separator {
-							padding: 0 4px;
-						}
-
-						> .type {
-							opacity: 0.7;
-
-							> .icon {
-								margin-right: 4px;
-							}
-						}
-
-						> .data-size {
-							opacity: 0.7;
-						}
-
-						> .created-at {
-							opacity: 0.7;
-
-							> [data-icon] {
-								margin-right: 2px;
-							}
-						}
-
-						> .nsfw {
-							color: #bf4633;
-						}
-					}
-				}
-			}
-		}
-	}
 }
 </style>
diff --git a/src/client/scripts/select-drive-file.ts b/src/client/scripts/select-drive-file.ts
index 004ddf2fd9..798c270e3f 100644
--- a/src/client/scripts/select-drive-file.ts
+++ b/src/client/scripts/select-drive-file.ts
@@ -3,6 +3,7 @@ import DriveWindow from '../components/drive-window.vue';
 export function selectDriveFile($root: any, multiple) {
 	return new Promise((res, rej) => {
 		const w = $root.new(DriveWindow, {
+			type: 'file',
 			multiple
 		});
 		w.$once('selected', files => {
diff --git a/src/client/scripts/select-drive-folder.ts b/src/client/scripts/select-drive-folder.ts
new file mode 100644
index 0000000000..68516e1010
--- /dev/null
+++ b/src/client/scripts/select-drive-folder.ts
@@ -0,0 +1,13 @@
+import DriveWindow from '../components/drive-window.vue';
+
+export function selectDriveFolder($root: any, multiple) {
+	return new Promise((res, rej) => {
+		const w = $root.new(DriveWindow, {
+			type: 'folder',
+			multiple
+		});
+		w.$once('selected', folders => {
+			res(multiple ? folders : (folders.length === 0 ? null : folders[0]));
+		});
+	});
+}
diff --git a/webpack.config.ts b/webpack.config.ts
index ece4854e6a..c6dc0dbabe 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -135,7 +135,7 @@ module.exports = {
 	output: {
 		path: __dirname + '/built/client/assets',
 		filename: `[name].${meta.version}.js`,
-		chunkFilename: '[hash:5].[id].js',
+		chunkFilename: '[fullhash].[id].js',
 		publicPath: `/assets/`
 	},
 	resolve: {
@@ -155,7 +155,7 @@ module.exports = {
 	optimization: {
 		minimizer: [new TerserPlugin()]
 	},
-	cache: true,
+	cache: false,
 	devtool: false, //'source-map',
 	mode: isProduction ? 'production' : 'development'
 };