diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs
index 26beabb7220552d2c867a3070d05c63f73147e8e..774ebd578a4cef51c5f445ecb86f46c481f2bdcb 100644
--- a/src-tauri/src/cmds.rs
+++ b/src-tauri/src/cmds.rs
@@ -43,9 +43,10 @@ pub async fn import_profile(
 #[tauri::command]
 pub async fn create_profile(
   item: PrfItem, // partial
+  file_data: Option<String>,
   profiles_state: State<'_, ProfilesState>,
 ) -> Result<(), String> {
-  let item = wrap_err!(PrfItem::from(item).await)?;
+  let item = wrap_err!(PrfItem::from(item, file_data).await)?;
   let mut profiles = profiles_state.0.lock().unwrap();
 
   wrap_err!(profiles.append_item(item))
diff --git a/src-tauri/src/core/profiles.rs b/src-tauri/src/core/profiles.rs
index a7211c1a032e9e597278a21d2c5f2c2fdbb5b3e3..0d86bacaef3001b437f03f180ffd3509a492f903 100644
--- a/src-tauri/src/core/profiles.rs
+++ b/src-tauri/src/core/profiles.rs
@@ -119,7 +119,7 @@ impl Default for PrfItem {
 impl PrfItem {
   /// From partial item
   /// must contain `itype`
-  pub async fn from(item: PrfItem) -> Result<PrfItem> {
+  pub async fn from(item: PrfItem, file_data: Option<String>) -> Result<PrfItem> {
     if item.itype.is_none() {
       bail!("type should not be null");
     }
@@ -137,7 +137,7 @@ impl PrfItem {
       "local" => {
         let name = item.name.unwrap_or("Local File".into());
         let desc = item.desc.unwrap_or("".into());
-        PrfItem::from_local(name, desc)
+        PrfItem::from_local(name, desc, file_data)
       }
       "merge" => {
         let name = item.name.unwrap_or("Merge".into());
@@ -155,7 +155,7 @@ impl PrfItem {
 
   /// ## Local type
   /// create a new item from name/desc
-  pub fn from_local(name: String, desc: String) -> Result<PrfItem> {
+  pub fn from_local(name: String, desc: String, file_data: Option<String>) -> Result<PrfItem> {
     let uid = help::get_uid("l");
     let file = format!("{uid}.yaml");
 
@@ -170,7 +170,7 @@ impl PrfItem {
       extra: None,
       option: None,
       updated: Some(help::get_now()),
-      file_data: Some(tmpl::ITEM_LOCAL.into()),
+      file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())),
     })
   }
 
diff --git a/src/components/profile/file-input.tsx b/src/components/profile/file-input.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..476fa2cad58a39985f7ac6cb1f0f8c37ec5e1acf
--- /dev/null
+++ b/src/components/profile/file-input.tsx
@@ -0,0 +1,61 @@
+import { useRef, useState } from "react";
+import { useLockFn } from "ahooks";
+import { Box, Button, Typography } from "@mui/material";
+
+interface Props {
+  onChange: (value: string) => void;
+}
+
+const FileInput = (props: Props) => {
+  const { onChange } = props;
+
+  // file input
+  const inputRef = useRef<any>();
+  const [loading, setLoading] = useState(false);
+  const [fileName, setFileName] = useState("");
+
+  const onFileInput = useLockFn(async (e: any) => {
+    const file = e.target.files?.[0] as File;
+
+    if (!file) return;
+
+    setFileName(file.name);
+    setLoading(true);
+
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onload = (event) => {
+        resolve(null);
+        onChange(event.target?.result as string);
+      };
+      reader.onerror = reject;
+      reader.readAsText(file);
+    }).finally(() => setLoading(false));
+  });
+
+  return (
+    <Box sx={{ mt: 2, mb: 1, display: "flex", alignItems: "center" }}>
+      <Button
+        variant="outlined"
+        sx={{ flex: "none" }}
+        onClick={() => inputRef.current?.click()}
+      >
+        Choose File
+      </Button>
+
+      <input
+        type="file"
+        accept=".yaml,.yml"
+        ref={inputRef}
+        style={{ display: "none" }}
+        onChange={onFileInput}
+      />
+
+      <Typography noWrap sx={{ ml: 1 }}>
+        {loading ? "Loading..." : fileName}
+      </Typography>
+    </Box>
+  );
+};
+
+export default FileInput;
diff --git a/src/components/profile/profile-new.tsx b/src/components/profile/profile-new.tsx
index a52913cfbef5087748594e22ef78a2783836ed00..10a24ade66183cdb12f637285cd5cb80cb205713 100644
--- a/src/components/profile/profile-new.tsx
+++ b/src/components/profile/profile-new.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useRef, useState } from "react";
 import { useSWRConfig } from "swr";
 import { useLockFn, useSetState } from "ahooks";
 import {
@@ -17,6 +17,7 @@ import {
 import { Settings } from "@mui/icons-material";
 import { createProfile } from "../../services/cmds";
 import Notice from "../base/base-notice";
+import FileInput from "./file-input";
 
 interface Props {
   open: boolean;
@@ -37,9 +38,10 @@ const ProfileNew = (props: Props) => {
   });
 
   const [showOpt, setShowOpt] = useState(false);
-  const [option, setOption] = useSetState({
-    user_agent: "",
-  }); // able to add more option
+  // can add more option
+  const [option, setOption] = useSetState({ user_agent: "" });
+  // file input
+  const fileDataRef = useRef<string | null>(null);
 
   const onCreate = useLockFn(async () => {
     if (!form.type) {
@@ -55,10 +57,15 @@ const ProfileNew = (props: Props) => {
       }
 
       const option_ = form.type === "remote" ? option : undefined;
-      await createProfile({ ...form, name, option: option_ });
+      const item = { ...form, name, option: option_ };
+      const fileData = form.type === "local" ? fileDataRef.current : null;
+
+      await createProfile(item, fileData);
+
       setForm({ type: "remote", name: "", desc: "", url: "" });
       setOption({ user_agent: "" });
       setShowOpt(false);
+      fileDataRef.current = null;
 
       mutate("getProfiles");
       onClose();
@@ -97,6 +104,7 @@ const ProfileNew = (props: Props) => {
         <TextField
           {...textFieldProps}
           label="Name"
+          autoComplete="off"
           value={form.name}
           onChange={(e) => setForm({ name: e.target.value })}
         />
@@ -104,6 +112,7 @@ const ProfileNew = (props: Props) => {
         <TextField
           {...textFieldProps}
           label="Descriptions"
+          autoComplete="off"
           value={form.desc}
           onChange={(e) => setForm({ desc: e.target.value })}
         />
@@ -112,15 +121,21 @@ const ProfileNew = (props: Props) => {
           <TextField
             {...textFieldProps}
             label="Subscription Url"
+            autoComplete="off"
             value={form.url}
             onChange={(e) => setForm({ url: e.target.value })}
           />
         )}
 
+        {form.type === "local" && (
+          <FileInput onChange={(val) => (fileDataRef.current = val)} />
+        )}
+
         {showOpt && (
           <TextField
             {...textFieldProps}
             label="User Agent"
+            autoComplete="off"
             value={option.user_agent}
             onChange={(e) => setOption({ user_agent: e.target.value })}
           />
diff --git a/src/services/cmds.ts b/src/services/cmds.ts
index 6dc28d3573620cb58b934b512100589009057b75..06a4ecdc88d2cb23a6efdc14f3b9cc4c5d901ccc 100644
--- a/src/services/cmds.ts
+++ b/src/services/cmds.ts
@@ -14,8 +14,11 @@ export async function enhanceProfiles() {
   return invoke<void>("enhance_profiles");
 }
 
-export async function createProfile(item: Partial<CmdType.ProfileItem>) {
-  return invoke<void>("create_profile", { item });
+export async function createProfile(
+  item: Partial<CmdType.ProfileItem>,
+  fileData?: string | null
+) {
+  return invoke<void>("create_profile", { item, fileData });
 }
 
 export async function viewProfile(index: string) {